1 package com.atlassian.vcache.internal.harness;
2
3 import com.atlassian.cache.CacheFactory;
4 import com.atlassian.cache.memory.MemoryCacheManager;
5 import com.atlassian.marshalling.jdk.JavaSerializationMarshalling;
6 import com.atlassian.vcache.ChangeRate;
7 import com.atlassian.vcache.DirectExternalCache;
8 import com.atlassian.vcache.ExternalCacheSettingsBuilder;
9 import com.atlassian.vcache.JvmCache;
10 import com.atlassian.vcache.JvmCacheSettingsBuilder;
11 import com.atlassian.vcache.RequestCache;
12 import com.atlassian.vcache.internal.core.DefaultVCacheCreationHandler;
13 import com.atlassian.vcache.internal.core.WorkContextRequestContextSupplier;
14 import com.atlassian.vcache.internal.core.metrics.DefaultMetricsCollector;
15 import com.atlassian.vcache.internal.core.metrics.MetricsCollector;
16 import com.atlassian.vcache.internal.core.metrics.NoopMetricsCollector;
17 import com.atlassian.vcache.internal.core.service.AbstractVCacheService;
18 import com.atlassian.vcache.internal.legacy.LegacyServiceSettings;
19 import com.atlassian.vcache.internal.legacy.LegacyServiceSettingsBuilder;
20 import com.atlassian.vcache.internal.legacy.LegacyVCacheService;
21 import com.atlassian.vcache.internal.memcached.MemcachedVCacheService;
22 import com.atlassian.vcache.internal.memcached.MemcachedVCacheServiceSettings;
23 import com.atlassian.vcache.internal.memcached.MemcachedVCacheServiceSettingsBuilder;
24 import com.atlassian.vcache.internal.test.EmptyVCacheSettingsDefaultsProvider;
25 import com.atlassian.vcache.internal.test.ThreadLocalRequestContextSupplier;
26 import com.codahale.metrics.MetricRegistry;
27 import com.codahale.metrics.Snapshot;
28 import net.spy.memcached.AddrUtil;
29 import net.spy.memcached.BinaryConnectionFactory;
30 import net.spy.memcached.MemcachedClient;
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
33
34 import java.io.IOException;
35 import java.text.DecimalFormat;
36 import java.time.Duration;
37 import java.util.Arrays;
38 import java.util.HashMap;
39 import java.util.List;
40 import java.util.Map;
41 import java.util.concurrent.TimeUnit;
42 import java.util.stream.Collectors;
43 import java.util.stream.IntStream;
44
45 import static java.util.Objects.requireNonNull;
46 import static java.util.stream.Collectors.joining;
47
48
49
50
51 public class StressHarness {
52 private static final Logger log = LoggerFactory.getLogger(StressHarness.class);
53
54 private static final ThreadLocalRequestContextSupplier requestContextSupplier = ThreadLocalRequestContextSupplier.strictSupplier();
55 private static final WorkContextRequestContextSupplier workContextContextSupplier = new WorkContextRequestContextSupplier(() -> "tenant-123");
56 private static final CacheFactory cacheFactory = new MemoryCacheManager();
57
58 private final MetricRegistry metricRegistry = new MetricRegistry();
59 private final AbstractVCacheService service;
60 private OverallConfig overallConfig;
61
62 public StressHarness(AbstractVCacheService service) {
63 this.service = requireNonNull(service);
64 }
65
66 public static void main(String[] args) throws InterruptedException, IOException {
67 log.info("And away");
68
69 final boolean useLegacy = false;
70 final LegacyServiceSettings settings = new LegacyServiceSettingsBuilder().build();
71 final MetricsCollector metricsCollector = new DefaultMetricsCollector(requestContextSupplier);
72
73 final AbstractVCacheService legacySvc = new LegacyVCacheService(
74 "harness",
75 requestContextSupplier,
76 workContextContextSupplier,
77 new EmptyVCacheSettingsDefaultsProvider(),
78 new DefaultVCacheCreationHandler(
79 10_000, Duration.ofHours(2), 10_000, ChangeRate.HIGH_CHANGE, ChangeRate.HIGH_CHANGE),
80 metricsCollector,
81 () -> cacheFactory,
82 settings,
83 context -> {
84 });
85
86 final MemcachedClient memcachedClient = new MemcachedClient(
87 new BinaryConnectionFactory(),
88 AddrUtil.getAddresses("192.168.99.100:32768"));
89
90 final MemcachedVCacheServiceSettings serviceSettings = new MemcachedVCacheServiceSettingsBuilder()
91 .productIdentifier("" + System.nanoTime())
92 .clientSupplier(() -> memcachedClient)
93 .threadLocalContextSupplier(requestContextSupplier)
94 .defaultsProvider(new EmptyVCacheSettingsDefaultsProvider())
95 .creationHandler(new DefaultVCacheCreationHandler(
96 10_000, Duration.ofHours(2), 10_000, ChangeRate.HIGH_CHANGE, ChangeRate.HIGH_CHANGE))
97 .metricsCollector(metricsCollector)
98 .begunTransactionalActivityHandler(context -> {
99 })
100 .build();
101 final AbstractVCacheService memcachedSvc = new MemcachedVCacheService(serviceSettings);
102
103 final StressHarness harness = new StressHarness(useLegacy ? legacySvc : memcachedSvc);
104
105 harness.setup();
106 harness.perform();
107
108 System.out.printf(
109 "\n\nFinished: serializeHack is '%s', collecting metrics is '%s', use legacy is '%s'\n",
110 settings.isSerializationHack(), !(metricsCollector instanceof NoopMetricsCollector), useLegacy);
111 }
112
113 private void perform() throws InterruptedException {
114
115
116
117 final List<Worker> workers = IntStream.rangeClosed(1, 10)
118 .mapToObj(i -> new Worker(i, overallConfig))
119 .collect(Collectors.toList());
120
121 workers.forEach(w -> new Thread(w).start());
122 Thread.sleep(60_000);
123 workers.forEach(Worker::stopIt);
124 Thread.sleep(500);
125
126 final List<String> columns = Arrays.asList("Timer", "Count", "Min", "Max", "Median", "95th", "99th");
127 System.out.println(columns.stream().collect(joining("\t")));
128 metricRegistry.getTimers().entrySet().forEach(timerEntry -> {
129 final Snapshot snapshot = timerEntry.getValue().getSnapshot();
130 final List<String> parts = Arrays.asList(
131 timerEntry.getKey(),
132 Long.toString(timerEntry.getValue().getCount()),
133 toMillisString(snapshot.getMin()),
134 toMillisString(snapshot.getMax()),
135 toMillisString(snapshot.getMedian()),
136 toMillisString(snapshot.get95thPercentile()),
137 toMillisString(snapshot.get99thPercentile()));
138
139 System.out.println(parts.stream().collect(joining("\t")));
140 });
141 }
142
143 private String toMillisString(double nanoseconds) {
144 return new DecimalFormat("#0.0#####").format(
145 nanoseconds / TimeUnit.NANOSECONDS.convert(1, TimeUnit.MILLISECONDS));
146 }
147
148 private void setup() {
149 final Map<String, CacheConfig> cacheTestConfigMap = new HashMap<>();
150 overallConfig = new OverallConfig(metricRegistry, service, requestContextSupplier, cacheTestConfigMap, 5, 200);
151
152
153 final JvmCache<String, String> jvmCache1 = service.getJvmCache("jvmCache1", new JvmCacheSettingsBuilder().build());
154 final CacheConfig jvmCache1Config = new CacheConfig(jvmCache1, 10, 10, 10, 20, 90);
155
156
157
158 final RequestCache<String, String> requestCache1 = service.getRequestCache("requestCache1");
159 final CacheConfig requestCache1Config = new CacheConfig(requestCache1, 20, 20, 20, 40, 90);
160
161
162
163 final DirectExternalCache<String> directExternalCache = service.getDirectExternalCache(
164 "directEC1",
165 JavaSerializationMarshalling.pair(String.class),
166 new ExternalCacheSettingsBuilder().build());
167 final CacheConfig directExternalCacheConfig = new CacheConfig(directExternalCache, 20, 20, 20, 40, 90);
168 cacheTestConfigMap.put(directExternalCache.getName(), directExternalCacheConfig);
169 }
170 }