Skip to content

Commit 2ae64ff

Browse files
committed
Provide ability to choose key type and add/remove custom cells on the fly
1 parent e52f9b9 commit 2ae64ff

File tree

4 files changed

+230
-75
lines changed

4 files changed

+230
-75
lines changed

src/main/java/org/terracotta/tinypounder/DatasetConfiguration.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,20 @@
11
package org.terracotta.tinypounder;
22

33
public class DatasetConfiguration {
4+
private final String keyType;
45
private final String offheapResourceName;
56
private final String diskResourceName;
67
private final boolean useIndex;
78

8-
public DatasetConfiguration(String offheapResourceName, String diskResourceName, boolean useIndex) {
9+
public DatasetConfiguration(String keyType, String offheapResourceName, String diskResourceName, boolean useIndex) {
10+
this.keyType = keyType;
911
this.offheapResourceName = offheapResourceName;
1012
this.diskResourceName = diskResourceName;
1113
this.useIndex = useIndex;
1214
}
1315

16+
public String getKeyType() { return keyType; }
17+
1418
public String getOffheapResourceName() {
1519
return offheapResourceName;
1620
}

src/main/java/org/terracotta/tinypounder/DatasetManagerBusinessReflectionImpl.java

Lines changed: 146 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,8 @@
99
import java.lang.reflect.Method;
1010
import java.math.BigInteger;
1111
import java.net.URI;
12-
import java.util.Collection;
13-
import java.util.Map;
14-
import java.util.Random;
15-
import java.util.Set;
16-
import java.util.TreeMap;
17-
import java.util.concurrent.ConcurrentHashMap;
18-
import java.util.concurrent.ConcurrentMap;
19-
import java.util.concurrent.ScheduledExecutorService;
20-
import java.util.concurrent.ThreadLocalRandom;
21-
import java.util.concurrent.TimeUnit;
12+
import java.util.*;
13+
import java.util.concurrent.*;
2214
import java.util.function.Predicate;
2315
import java.util.regex.Matcher;
2416
import java.util.regex.Pattern;
@@ -38,8 +30,8 @@ public class DatasetManagerBusinessReflectionImpl {
3830
private Random random = new Random();
3931
private Object stringCellDefinition;
4032
private Class<?> cellDefinitionClass;
41-
private Object typeString;
4233
private Class<?> typeClass;
34+
private Set<String> customCells = (new ConcurrentHashMap<>()).newKeySet();
4335

4436
@Autowired
4537
public DatasetManagerBusinessReflectionImpl(KitAwareClassLoaderDelegator kitAwareClassLoaderDelegator, ScheduledExecutorService poundingScheduler) throws Exception {
@@ -58,11 +50,11 @@ public DatasetManagerBusinessReflectionImpl(KitAwareClassLoaderDelegator kitAwar
5850

5951
private void pound(Object datasetInstance, Integer intensity) {
6052
IntStream.range(0, intensity).forEach(value -> {
61-
insert(datasetInstance, Long.toString(ThreadLocalRandom.current().nextLong(0, intensity * 1000)), longString(intensity));
62-
update(datasetInstance, Long.toString(ThreadLocalRandom.current().nextLong(0, intensity * 1000)), longString(intensity));
63-
delete(datasetInstance, Long.toString(ThreadLocalRandom.current().nextLong(0, intensity * 1000)));
53+
insert(datasetInstance, ThreadLocalRandom.current().nextLong(0, intensity * 1000), intensity);
54+
update(datasetInstance, ThreadLocalRandom.current().nextLong(0, intensity * 1000), intensity);
55+
delete(datasetInstance, ThreadLocalRandom.current().nextLong(0, intensity * 1000));
6456
stream(datasetInstance);
65-
retrieve(datasetInstance, Long.toString(ThreadLocalRandom.current().nextLong(0, intensity * 1000)));
57+
retrieve(datasetInstance, ThreadLocalRandom.current().nextLong(0, intensity * 1000));
6658
});
6759
try {
6860
generateRandomFailure(datasetInstance);
@@ -75,10 +67,10 @@ private void generateRandomFailure(Object datasetInstance) {
7567
int nextInt = ThreadLocalRandom.current().nextInt(0, 5);
7668
switch (nextInt) {
7769
case 0:
78-
insert(datasetInstance, null, longString(0));
70+
insert(datasetInstance, null, 0);
7971
break;
8072
case 1:
81-
update(datasetInstance, null, longString(0));
73+
update(datasetInstance, null, 0);
8274
break;
8375
case 2:
8476
retrieve(datasetInstance, null);
@@ -155,126 +147,214 @@ private void stream(Object datasetInstance) {
155147
}
156148
}
157149

158-
private void delete(Object datasetInstance, String key) {
150+
private void delete(Object datasetInstance, Long key) {
159151
try {
160152
Thread.currentThread().setContextClassLoader(kitAwareClassLoaderDelegator.getUrlClassLoader());
161153
Object datasetWriterReader = retrieveDatasetWriterReader(datasetInstance);
162154
Class<?> datasetWriterReaderClass = loadClass("com.terracottatech.store.DatasetWriterReader");
163155
Method deleteMethod = datasetWriterReaderClass.getMethod("delete", Comparable.class);
164-
deleteMethod.invoke(datasetWriterReader, key);
156+
deleteMethod.invoke(datasetWriterReader, longToKeyType(getKeyTypeJDK(datasetInstance), key));
165157
} catch (Exception e) {
166158
throw new RuntimeException(e);
167159
}
168160
}
169161

170-
private void update(Object datasetInstance, String key, String value) {
162+
private void update(Object datasetInstance, Long key, Integer value) {
171163
try {
172164
Thread.currentThread().setContextClassLoader(kitAwareClassLoaderDelegator.getUrlClassLoader());
173165
Object datasetWriterReader = retrieveDatasetWriterReader(datasetInstance);
174166
Class<?> datasetWriterReaderClass = loadClass("com.terracottatech.store.DatasetWriterReader");
175167

176168
Class<?> updateOperationClass = loadClass("com.terracottatech.store.UpdateOperation");
177169
Method writeMethod = updateOperationClass.getMethod("write", cellDefinitionClass, Object.class);
178-
Object writeOperation = writeMethod.invoke(null, stringCellDefinition, value);
170+
Object writeOperation = writeMethod.invoke(null, stringCellDefinition, longString(value));
179171

180172
Method updateMethod = datasetWriterReaderClass.getMethod("update", Comparable.class, updateOperationClass);
181173

182-
updateMethod.invoke(datasetWriterReader, key, writeOperation);
174+
updateMethod.invoke(datasetWriterReader, longToKeyType(getKeyTypeJDK(datasetInstance), key), writeOperation);
183175
} catch (Exception e) {
184176
throw new RuntimeException(e);
185177
}
186178
}
187179

188-
private void retrieve(Object datasetInstance, String key) {
180+
private void retrieve(Object datasetInstance, Long key) {
189181
try {
190182
Thread.currentThread().setContextClassLoader(kitAwareClassLoaderDelegator.getUrlClassLoader());
191183
Object datasetWriterReader = retrieveDatasetWriterReader(datasetInstance);
192184
Class<?> datasetWriterReaderClass = loadClass("com.terracottatech.store.DatasetWriterReader");
193185
Method getMethod = datasetWriterReaderClass.getMethod("get", Comparable.class);
194-
getMethod.invoke(datasetWriterReader, key);
186+
getMethod.invoke(datasetWriterReader, longToKeyType(getKeyTypeJDK(datasetInstance), key));
195187
} catch (Exception e) {
196188
throw new RuntimeException(e);
197189
}
198190
}
199191

200192
private Object retrieveDatasetWriterReader(Object datasetInstance) throws Exception {
201193
Class<?> internalDatasetClass = loadClass("com.terracottatech.store.internal.InternalDataset");
194+
Method writerReader = internalDatasetClass.getMethod("writerReader");
195+
return writerReader.invoke(datasetInstance);
196+
}
202197

198+
private Object retrieveDatasetReader(Object datasetInstance) throws Exception {
199+
Class<?> internalDatasetClass = loadClass("com.terracottatech.store.internal.InternalDataset");
200+
Method reader = internalDatasetClass.getMethod("reader");
201+
return reader.invoke(datasetInstance);
202+
}
203203

204-
Class<?> readVisibilityClas = loadClass("com.terracottatech.store.setting.ReadVisibility");
205-
Class<?> readSettingsClass = loadClass("com.terracottatech.store.setting.ReadSettings");
206-
207-
Class<?> writeVisibilityClas = loadClass("com.terracottatech.store.setting.WriteVisibility");
208-
Class<?> writeSettingsClass = loadClass("com.terracottatech.store.setting.WriteSettings");
209-
210-
211-
Field definitiveField = readVisibilityClas.getDeclaredField("DEFINITIVE");
212-
Object definitiveReadVisibility = definitiveField.get(null);
213-
Method asReadSettingsMethod = readVisibilityClas.getMethod("asReadSettings");
214-
Object definitiveReadVisibilityAsReadSettings = asReadSettingsMethod.invoke(definitiveReadVisibility);
215-
216-
217-
Field immediateField = writeVisibilityClas.getDeclaredField("IMMEDIATE");
218-
Object immediateWriteVisibility = immediateField.get(null);
219-
Method asWriteSettingsMethod = writeVisibilityClas.getMethod("asWriteSettings");
220-
Object immediateWriteVisibilityAsWriteSettings = asWriteSettingsMethod.invoke(immediateWriteVisibility);
221-
222-
Method writerReader = internalDatasetClass.getMethod("writerReader", readSettingsClass, writeSettingsClass);
204+
private Object longToKeyType(Class keyTypeJDK, Long internalKey) {
205+
Object key;
206+
if (keyTypeJDK.equals(String.class)) {
207+
key = Long.toString(internalKey);
208+
} else if (keyTypeJDK.equals(Integer.class)) {
209+
key = internalKey.intValue();
210+
} else if (keyTypeJDK.equals(Long.class)) {
211+
key = internalKey;
212+
} else if (keyTypeJDK.equals(Double.class)) {
213+
key = internalKey.doubleValue();
214+
} else if (keyTypeJDK.equals(Boolean.class)) {
215+
key = internalKey % 2 == 0;
216+
} else if (keyTypeJDK.equals(Character.class)) {
217+
key = Long.toString(internalKey).charAt(0);
218+
} else {
219+
key = null;
220+
}
221+
return key;
222+
}
223223

224-
return writerReader.invoke(datasetInstance, definitiveReadVisibilityAsReadSettings, immediateWriteVisibilityAsWriteSettings);
224+
private Class<?> getKeyTypeJDK(Object datasetInstance) throws Exception {
225+
Class<?> datasetReaderClass = loadClass("com.terracottatech.store.DatasetReader");
226+
Method getKeyTypeMethod = datasetReaderClass.getMethod("getKeyType");
227+
Object datasetReader = retrieveDatasetReader(datasetInstance);
228+
Object keyType = getKeyTypeMethod.invoke(datasetReader);
229+
Method getJDKTypeMethod = typeClass.getDeclaredMethod("getJDKType");
230+
return (Class<?>) getJDKTypeMethod.invoke(keyType);
225231
}
226232

227-
private void insert(Object datasetInstance, String key, String value) {
233+
private void insert(Object datasetInstance, Long key, Integer value) {
228234
try {
229235
Thread.currentThread().setContextClassLoader(kitAwareClassLoaderDelegator.getUrlClassLoader());
230236
Object datasetWriterReader = retrieveDatasetWriterReader(datasetInstance);
231-
232237
Class<?> datasetWriterReaderClass = loadClass("com.terracottatech.store.DatasetWriterReader");
233238

234239
Class<?> cellClass = loadClass("com.terracottatech.store.Cell");
235240
Class cellClasses = Array.newInstance(cellClass, 0).getClass();
236241
Method addMethod = datasetWriterReaderClass.getMethod("add", Comparable.class, cellClasses);
237242

238-
Object[] cells;
239-
if (key == null || Long.parseLong(key) % 2 == 0) {
240-
cells = generateOneCell(value, cellClass);
243+
Object[] generatedCells;
244+
if (key == null || key % 2 == 0) {
245+
generatedCells = generateOneCell(value, cellClass);
241246
} else {
242-
cells = generateTwoCells(value, cellClass);
247+
generatedCells = generateTwoCells(value, cellClass);
243248
}
244-
245-
addMethod.invoke(datasetWriterReader, key, cells);
246-
249+
Object[] customCells = generateCustomCells(value);
250+
Object[] cells = (Object[]) Array.newInstance(cellClass, generatedCells.length + customCells.length);
251+
int i = 0;
252+
for (Object c : generatedCells) {
253+
cells[i++] = c;
254+
}
255+
for (Object c : customCells) {
256+
cells[i++] = c;
257+
}
258+
addMethod.invoke(datasetWriterReader, longToKeyType(getKeyTypeJDK(datasetInstance), key), cells);
247259
} catch (Exception e) {
248260
throw new RuntimeException(e);
249261
}
250262
}
251263

252-
private Object[] generateTwoCells(String value, Class<?> cellClass) throws Exception {
264+
private Object[] generateTwoCells(Integer value, Class<?> cellClass) throws Exception {
265+
String valueStr = longString(value);
253266
Method newCellMethod = cellDefinitionClass.getMethod("newCell", Object.class);
254-
Object stringCellValue = newCellMethod.invoke(stringCellDefinition, value);
267+
Object stringCellValue = newCellMethod.invoke(stringCellDefinition, valueStr);
255268

256269
Method defineBytesMethod = cellDefinitionClass.getMethod("defineBytes", String.class);
257270
Object bytesCellDefinition = defineBytesMethod.invoke(null, "myBytesCell");
258-
Object bytesCellValue = newCellMethod.invoke(bytesCellDefinition, value.getBytes());
271+
Object bytesCellValue = newCellMethod.invoke(bytesCellDefinition, valueStr.getBytes());
259272

260273
Object[] cells = (Object[]) Array.newInstance(cellClass, 2);
261274
cells[0] = stringCellValue;
262275
cells[1] = bytesCellValue;
263276
return cells;
264277
}
265278

266-
private Object[] generateOneCell(String value, Class<?> cellClass) throws Exception {
279+
private Object[] generateOneCell(Integer value, Class<?> cellClass) throws Exception {
280+
String valueStr = longString(value);
267281
Class<?> cellDefinitionClass = loadClass("com.terracottatech.store.definition.CellDefinition");
268282
Method newCellMethod = cellDefinitionClass.getMethod("newCell", Object.class);
269283
Method defineBytesMethod = cellDefinitionClass.getMethod("defineBytes", String.class);
270284
Object bytesCellDefinition = defineBytesMethod.invoke(null, "myBytesCell");
271-
Object bytesCellValue = newCellMethod.invoke(bytesCellDefinition, value.getBytes());
285+
Object bytesCellValue = newCellMethod.invoke(bytesCellDefinition, valueStr.getBytes());
272286

273287
Object[] cells = (Object[]) Array.newInstance(cellClass, 1);
274288
cells[0] = bytesCellValue;
275289
return cells;
276290
}
277291

292+
private Object[] generateCustomCells(Integer value) throws Exception {
293+
String valueStr = longString(value);
294+
Method newCellMethod = cellDefinitionClass.getMethod("newCell", Object.class);
295+
List<Object> cells = new ArrayList<>();
296+
for (String customCellStr : customCells) {
297+
String[] splitted = customCellStr.split(":");
298+
String cellName = splitted[0];
299+
String cellType = splitted[1];
300+
switch(cellType) {
301+
case "STRING":
302+
Object stringCellDefinition = cellDefinitionClass
303+
.getMethod("defineString", String.class).invoke(null, cellName);
304+
cells.add(newCellMethod.invoke(stringCellDefinition, valueStr));
305+
break;
306+
case "INT":
307+
Object intCellDefinition = cellDefinitionClass
308+
.getMethod("defineInt", String.class).invoke(null, cellName);
309+
cells.add(newCellMethod.invoke(intCellDefinition, ThreadLocalRandom.current().nextInt(0, value * 1000)));
310+
break;
311+
case "LONG":
312+
Object longCellDefinition = cellDefinitionClass
313+
.getMethod("defineLong", String.class).invoke(null, cellName);
314+
cells.add(newCellMethod.invoke(longCellDefinition, ThreadLocalRandom.current().nextLong(0, value * 1000)));
315+
break;
316+
case "DOUBLE":
317+
Object doubleCellDefinition = cellDefinitionClass
318+
.getMethod("defineDouble", String.class).invoke(null, cellName);
319+
cells.add(newCellMethod.invoke(doubleCellDefinition, ThreadLocalRandom.current().nextDouble(0, value * 1000)));
320+
break;
321+
case "BOOL":
322+
Object boolCellDefinition = cellDefinitionClass
323+
.getMethod("defineBool", String.class).invoke(null, cellName);
324+
cells.add(newCellMethod.invoke(boolCellDefinition, ThreadLocalRandom.current().nextInt(0, value * 1000) % 2 == 0));
325+
break;
326+
case "CHAR":
327+
Object charCellDefinition = cellDefinitionClass
328+
.getMethod("defineChar", String.class).invoke(null, cellName);
329+
cells.add(newCellMethod.invoke(charCellDefinition, valueStr.charAt(0)));
330+
break;
331+
case "BYTES":
332+
Object bytesCellDefinition = cellDefinitionClass
333+
.getMethod("defineBytes", String.class).invoke(null, cellName);
334+
cells.add(newCellMethod.invoke(bytesCellDefinition, valueStr.getBytes()));
335+
break;
336+
default:
337+
throw new RuntimeException("Cannot recognize cell type: " + cellType);
338+
}
339+
}
340+
return cells.toArray();
341+
}
342+
343+
public void addCustomCell(String cellStr) {
344+
String[] splitted = cellStr.split(":");
345+
if (splitted.length == 2) {
346+
String cellType = splitted[1];
347+
Set<String> TYPES = new HashSet<>(Arrays.asList("STRING", "INT", "LONG", "DOUBLE", "BOOL", "CHAR", "BYTES"));
348+
if (TYPES.contains(cellType)) {
349+
customCells.add(cellStr);
350+
}
351+
}
352+
}
353+
354+
public void removeCustomCell(String cellStr) {
355+
customCells.remove(cellStr);
356+
}
357+
278358
private String longString(Integer intensity) {
279359
return new BigInteger(intensity * 10, random).toString(16);
280360
}
@@ -334,8 +414,6 @@ public void initializeDatasetManager(String terracottaServerUrl) {
334414

335415
private void initCommonObjectsAndClasses() throws Exception {
336416
typeClass = loadClass("com.terracottatech.store.Type");
337-
Field typeStringField = typeClass.getDeclaredField("STRING");
338-
typeString = typeStringField.get(null);
339417

340418
cellDefinitionClass = loadClass("com.terracottatech.store.definition.CellDefinition");
341419
Method defineStringMethod = cellDefinitionClass.getMethod("defineString", String.class);
@@ -403,7 +481,7 @@ public void createDataset(String datasetName, DatasetConfiguration datasetConfig
403481
Object datasetConfigurationBuilt = buildMethod.invoke(datasetConfigurationBuilder);
404482

405483
Method createDatasetMethod = datasetManagerClass.getMethod("createDataset", String.class, typeClass, datasetConfigurationClass);
406-
Object datasetInstance = createDatasetMethod.invoke(datasetManager, datasetName, typeString, datasetConfigurationBuilt);
484+
Object datasetInstance = createDatasetMethod.invoke(datasetManager, datasetName, toKeyType(datasetConfiguration.getKeyType()), datasetConfigurationBuilt);
407485

408486
String instanceName = getInstanceName(datasetInstance);
409487
Map<String, Object> instancesByName = new TreeMap<>();
@@ -414,6 +492,10 @@ public void createDataset(String datasetName, DatasetConfiguration datasetConfig
414492
}
415493
}
416494

495+
private Object toKeyType(String keyTypeStr) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
496+
return loadClass("com.terracottatech.store.Type").getDeclaredField(keyTypeStr).get(null);
497+
}
498+
417499
private String getInstanceName(Object datasetInstance) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException {
418500
Class<?> manageableDatasetClass = loadClass("com.terracottatech.store.internal.InternalDataset");
419501
Method getStatisticsMethod = manageableDatasetClass.getMethod("getStatistics");
@@ -478,9 +560,10 @@ public void closeDatasetInstance(String datasetName, String instanceName) {
478560
public String createDatasetInstance(String datasetName) {
479561
try {
480562
Thread.currentThread().setContextClassLoader(kitAwareClassLoaderDelegator.getUrlClassLoader());
481-
563+
Method listDatasetsMethod = datasetManagerClass.getMethod("listDatasets");
564+
Map<String, Object> datasetsByName = (Map<String, Object>) listDatasetsMethod.invoke(datasetManager);
482565
Method getDatasetMethod = datasetManagerClass.getMethod("getDataset", String.class, typeClass);
483-
Object datasetInstance = getDatasetMethod.invoke(datasetManager, datasetName, typeString);
566+
Object datasetInstance = getDatasetMethod.invoke(datasetManager, datasetName, datasetsByName.get(datasetName));
484567
String instanceName = getInstanceName(datasetInstance);
485568

486569
datasetInstancesByDatasetName.computeIfAbsent(datasetName, k -> new TreeMap<>());

0 commit comments

Comments
 (0)