PageRenderTime 50ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 1ms

/chronicle/src/test/java/com/higherfrequencytrading/chronicle/datamodel/MapWrapperTest.java

http://github.com/peter-lawrey/Java-Chronicle
Java | 444 lines | 342 code | 67 blank | 35 comment | 23 complexity | beae5a661ddfb08fbfda824e0e2e462a MD5 | raw file
  1. /*
  2. * Copyright 2013 Peter Lawrey
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package com.higherfrequencytrading.chronicle.datamodel;
  17. import com.higherfrequencytrading.chronicle.Chronicle;
  18. import com.higherfrequencytrading.chronicle.impl.IndexedChronicle;
  19. import com.higherfrequencytrading.chronicle.tcp.InProcessChronicleSink;
  20. import com.higherfrequencytrading.chronicle.tcp.InProcessChronicleSource;
  21. import com.higherfrequencytrading.chronicle.tools.ChronicleTools;
  22. import org.junit.Test;
  23. import java.io.IOException;
  24. import java.util.LinkedHashMap;
  25. import java.util.Map;
  26. import java.util.concurrent.atomic.AtomicInteger;
  27. import static org.easymock.EasyMock.*;
  28. import static org.junit.Assert.assertEquals;
  29. import static org.junit.Assert.assertNotNull;
  30. /**
  31. * @author peter.lawrey
  32. */
  33. public class MapWrapperTest {
  34. static final String TMP = System.getProperty("java.io.tmpdir");
  35. @Test
  36. public void testMethods() throws IOException {
  37. String name = TMP + "/set-methods";
  38. ChronicleTools.deleteOnExit(name);
  39. {
  40. MapListener stringsListener = createMock("strings", MapListener.class);
  41. stringsListener.eventStart(1, "strings");
  42. stringsListener.add("Hello", "hi");
  43. stringsListener.eventEnd(true);
  44. stringsListener.eventStart(3, "strings");
  45. stringsListener.add("World", "all");
  46. stringsListener.eventEnd(true);
  47. MapListener intListener = createMock("ints", MapListener.class);
  48. for (int i = 0; i < 3; i++) {
  49. intListener.eventStart(i * 2, "ints");
  50. intListener.add(i, i + 1000);
  51. intListener.eventEnd(true);
  52. }
  53. stringsListener.eventStart(5, "strings");
  54. stringsListener.onEvent("bye");
  55. stringsListener.eventEnd(true);
  56. intListener.eventStart(6, "ints");
  57. intListener.onEvent("now");
  58. intListener.eventEnd(true);
  59. stringsListener.inSync();
  60. intListener.inSync();
  61. replay(stringsListener);
  62. replay(intListener);
  63. Chronicle chronicle = new IndexedChronicle(name);
  64. DataStore dataStore = new DataStore(chronicle, ModelMode.MASTER);
  65. MapWrapper<String, String> strings = new MapWrapper<String, String>(dataStore, "strings", String.class, String.class, new LinkedHashMap<String, String>(), 16);
  66. strings.addListener(stringsListener);
  67. MapWrapper<Integer, Integer> ints = new MapWrapper<Integer, Integer>(dataStore, "ints", Integer.class, Integer.class, new LinkedHashMap<Integer, Integer>(), 16);
  68. ints.addListener(intListener);
  69. dataStore.start();
  70. ints.put(0, 1000);
  71. strings.put("Hello", "hi");
  72. ints.put(1, 1001);
  73. strings.put("World", "all");
  74. ints.put(2, 1002);
  75. strings.publishEvent("bye");
  76. ints.publishEvent("now");
  77. verify(stringsListener);
  78. verify(intListener);
  79. assertEquals("{Hello=hi, World=all}", strings.toString());
  80. assertEquals("{0=1000, 1=1001, 2=1002}", ints.toString());
  81. chronicle.close();
  82. }
  83. {
  84. MapListener stringsListener = createMock("strings", MapListener.class);
  85. stringsListener.eventStart(7, "strings");
  86. stringsListener.add("!", "end");
  87. stringsListener.eventEnd(true);
  88. MapListener intListener = createMock("ints", MapListener.class);
  89. intListener.eventStart(8, "ints");
  90. intListener.add(3, 1003);
  91. intListener.eventEnd(true);
  92. stringsListener.inSync();
  93. intListener.inSync();
  94. replay(stringsListener);
  95. replay(intListener);
  96. Chronicle chronicle = new IndexedChronicle(name);
  97. DataStore dataStore = new DataStore(chronicle, ModelMode.MASTER);
  98. MapWrapper<String, String> strings = new MapWrapper<String, String>(dataStore, "strings", String.class, String.class, new LinkedHashMap<String, String>(), 16);
  99. strings.addListener(stringsListener);
  100. MapWrapper<Integer, Integer> ints = new MapWrapper<Integer, Integer>(dataStore, "ints", Integer.class, Integer.class, new LinkedHashMap<Integer, Integer>(), 16);
  101. ints.addListener(intListener);
  102. // assume we have all the events written so far
  103. dataStore.start(chronicle.size() - 1);
  104. strings.put("!", "end");
  105. ints.put(3, 1003);
  106. verify(stringsListener);
  107. verify(intListener);
  108. assertEquals("{Hello=hi, World=all, !=end}", strings.toString());
  109. assertEquals("{0=1000, 1=1001, 2=1002, 3=1003}", ints.toString());
  110. chronicle.close();
  111. }
  112. }
  113. @Test
  114. public void testMapPerformance() throws IOException {
  115. String name = TMP + "/map-perf";
  116. ChronicleTools.deleteOnExit(name);
  117. long start = System.nanoTime();
  118. int size = 0;
  119. {
  120. Chronicle chronicle = new IndexedChronicle(name);
  121. DataStore dataStore = new DataStore(chronicle, ModelMode.MASTER);
  122. MapWrapper<String, String> strings = new MapWrapper<String, String>(dataStore, "strings", String.class, String.class, new LinkedHashMap<String, String>(), 16);
  123. MapWrapper<Integer, Integer> ints = new MapWrapper<Integer, Integer>(dataStore, "ints", Integer.class, Integer.class, new LinkedHashMap<Integer, Integer>(), 16);
  124. dataStore.start();
  125. ints.clear();
  126. strings.clear();
  127. for (int j = 0; j < 10000; j++) {
  128. for (int i = 0; i < 100; i++) {
  129. ints.put(i, i + j);
  130. strings.put(Integer.toString(i), Integer.toString(i + j));
  131. }
  132. size += Math.min(strings.size(), ints.size());
  133. for (int i = 0; i < 100; i++) {
  134. ints.remove(i);
  135. strings.remove(Integer.toString(i));
  136. }
  137. }
  138. chronicle.close();
  139. }
  140. long mid = System.nanoTime();
  141. {
  142. Chronicle chronicle = new IndexedChronicle(name);
  143. DataStore dataStore = new DataStore(chronicle, ModelMode.MASTER);
  144. MapWrapper<String, String> strings = new MapWrapper<String, String>(dataStore, "strings", String.class, String.class, new LinkedHashMap<String, String>(), 16);
  145. MapWrapper<Integer, Integer> ints = new MapWrapper<Integer, Integer>(dataStore, "ints", Integer.class, Integer.class, new LinkedHashMap<Integer, Integer>(), 16);
  146. dataStore.start();
  147. chronicle.close();
  148. }
  149. long end = System.nanoTime();
  150. System.out.printf("Took %.1f seconds avg to add&remove %,d elements and %.1f seconds avg to reload them%n",
  151. (mid - start) / 2e9, size, (end - mid) / 2e9);
  152. }
  153. @Test
  154. public void testOverTcp() throws IOException, InterruptedException {
  155. String name = TMP + "/testOverTcp0";
  156. String name2 = TMP + "/testOverTcp2";
  157. ChronicleTools.deleteOnExit(name);
  158. ChronicleTools.deleteOnExit(name2);
  159. long start = System.nanoTime();
  160. int PORT = 12346;
  161. int size = 0;
  162. InProcessChronicleSource chronicle = new InProcessChronicleSource(new IndexedChronicle(name), PORT);
  163. DataStore dataStore = new DataStore(chronicle, ModelMode.MASTER);
  164. MapWrapper<String, String> strings = new MapWrapper<String, String>(dataStore, "strings", String.class, String.class, new LinkedHashMap<String, String>(), 16);
  165. MapWrapper<Integer, Integer> ints = new MapWrapper<Integer, Integer>(dataStore, "ints", Integer.class, Integer.class, new LinkedHashMap<Integer, Integer>(), 16);
  166. dataStore.start();
  167. ints.clear();
  168. strings.clear();
  169. InProcessChronicleSink chronicle2 = new InProcessChronicleSink(new IndexedChronicle(name2), "localhost", PORT);
  170. DataStore dataStore2 = new DataStore(chronicle2, ModelMode.READ_ONLY);
  171. MapWrapper<String, String> strings2 = new MapWrapper<String, String>(dataStore2, "strings", String.class, String.class, new LinkedHashMap<String, String>(), 16);
  172. MapWrapper<Integer, Integer> ints2 = new MapWrapper<Integer, Integer>(dataStore2, "ints", Integer.class, Integer.class, new LinkedHashMap<Integer, Integer>(), 16);
  173. final AtomicInteger sai = new AtomicInteger();
  174. MapListener<String, String> stringsListener = new AbstractMapListener<String, String>() {
  175. @Override
  176. public void update(String key, String oldValue, String newValue) {
  177. // System.out.println(key + " " + oldValue + " => " + newValue);
  178. sai.incrementAndGet();
  179. }
  180. @Override
  181. public void inSync() {
  182. // System.out.println("inSync");
  183. }
  184. };
  185. strings2.addListener(stringsListener);
  186. final AtomicInteger iai = new AtomicInteger();
  187. MapListener<Integer, Integer> intsListener = new AbstractMapListener<Integer, Integer>() {
  188. @Override
  189. public void update(Integer key, Integer oldValue, Integer newValue) {
  190. // System.out.println(key + " " + oldValue + " => " + newValue);
  191. iai.incrementAndGet();
  192. }
  193. };
  194. ints2.addListener(intsListener);
  195. dataStore2.start();
  196. int count = 0;
  197. for (int j = 0; j < 1000; j++) {
  198. int collectionSize = 1000;
  199. for (int i = 0; i < collectionSize; i++) {
  200. ints.put(i, i + j);
  201. strings.put(Integer.toString(i), Integer.toString(i + j));
  202. }
  203. size += Math.min(strings.size(), ints.size());
  204. for (int i = 0; i < collectionSize; i++) {
  205. ints.remove(i);
  206. strings.remove(Integer.toString(i));
  207. }
  208. count += 4 * collectionSize;
  209. }
  210. long mid = System.nanoTime();
  211. // int timeout = 0;
  212. while (dataStore2.events() < count) {
  213. // if (timeout++ % 10000 == 0)
  214. // System.out.println(dataStore2.events());
  215. Thread.sleep(1);
  216. }
  217. long end = System.nanoTime();
  218. System.out.printf("Startup and write took %.2f us on average and read and shutdown took %.2f on average%n",
  219. (mid - start) / count / 1e3, (end - mid) / count / 1e3);
  220. // Thread.sleep(10000);
  221. chronicle.close();
  222. chronicle2.close();
  223. }
  224. @Test
  225. public void testOverTcpPutAllClear() throws IOException, InterruptedException {
  226. String name = TMP + "/testOverTcpPutAllClear0";
  227. String name2 = TMP + "/testOverTcpPutAllClear2";
  228. ChronicleTools.deleteOnExit(name);
  229. ChronicleTools.deleteOnExit(name2);
  230. long start = System.nanoTime();
  231. int PORT = 12347;
  232. InProcessChronicleSource chronicle = new InProcessChronicleSource(new IndexedChronicle(name), PORT);
  233. DataStore dataStore = new DataStore(chronicle, ModelMode.MASTER);
  234. MapWrapper<String, String> strings = new MapWrapper<String, String>(dataStore, "strings", String.class, String.class, new LinkedHashMap<String, String>(), 16);
  235. MapWrapper<Integer, Integer> ints = new MapWrapper<Integer, Integer>(dataStore, "ints", Integer.class, Integer.class, new LinkedHashMap<Integer, Integer>(), 16);
  236. dataStore.start();
  237. ints.clear();
  238. strings.clear();
  239. InProcessChronicleSink chronicle2 = new InProcessChronicleSink(new IndexedChronicle(name2), "localhost", PORT);
  240. DataStore dataStore2 = new DataStore(chronicle2, ModelMode.READ_ONLY);
  241. MapWrapper<String, String> strings2 = new MapWrapper<String, String>(dataStore2, "strings", String.class, String.class, new LinkedHashMap<String, String>(), 16);
  242. MapWrapper<Integer, Integer> ints2 = new MapWrapper<Integer, Integer>(dataStore2, "ints", Integer.class, Integer.class, new LinkedHashMap<Integer, Integer>(), 16);
  243. final AtomicInteger sai = new AtomicInteger();
  244. MapListener<String, String> stringsListener = new AbstractMapListener<String, String>() {
  245. @Override
  246. public void update(String key, String oldValue, String newValue) {
  247. // System.out.println(key + " " + oldValue + " => " + newValue);
  248. sai.incrementAndGet();
  249. }
  250. };
  251. strings2.addListener(stringsListener);
  252. final AtomicInteger iai = new AtomicInteger();
  253. MapListener<Integer, Integer> intsListener = new AbstractMapListener<Integer, Integer>() {
  254. @Override
  255. public void update(Integer key, Integer oldValue, Integer newValue) {
  256. // System.out.println(key + " " + oldValue + " => " + newValue);
  257. iai.incrementAndGet();
  258. }
  259. };
  260. ints2.addListener(intsListener);
  261. dataStore2.start();
  262. Map<String, String> ssMap = new LinkedHashMap<String, String>();
  263. Map<Integer, Integer> iiMap = new LinkedHashMap<Integer, Integer>();
  264. int count = 0;
  265. int collectionSize = 2000;
  266. for (int i = 0; i < collectionSize; i++) {
  267. iiMap.put(i, i);
  268. ssMap.put(Integer.toString(i), Integer.toString(i));
  269. }
  270. for (int j = 0; j < 2500; j++) {
  271. strings.putAll(ssMap);
  272. ints.putAll(iiMap);
  273. strings.clear();
  274. ints.clear();
  275. count += 4;
  276. }
  277. long mid = System.nanoTime();
  278. // int timeout = 0;
  279. while (dataStore2.events() < count) {
  280. Thread.sleep(1);
  281. }
  282. long end = System.nanoTime();
  283. System.out.printf("Startup and write took %.2f us on average (per key) and read and shutdown took %.2f us on average (per key)%n",
  284. (mid - start) / count / collectionSize / 1e3, (end - mid) / count / collectionSize / 1e3);
  285. chronicle.close();
  286. // System.gc();
  287. chronicle2.close();
  288. }
  289. @Test
  290. public void testOverTcpGetPerf() throws IOException, InterruptedException {
  291. String name = TMP + "/testOverTcpGetPerf0";
  292. String name2 = TMP + "/testOverTcpGetPerf2";
  293. ChronicleTools.deleteOnExit(name);
  294. ChronicleTools.deleteOnExit(name2);
  295. long start = System.nanoTime();
  296. int PORT = 12348;
  297. InProcessChronicleSource chronicle = new InProcessChronicleSource(new IndexedChronicle(name), PORT);
  298. DataStore dataStore = new DataStore(chronicle, ModelMode.MASTER);
  299. MapWrapper<String, String> strings = new MapWrapper<String, String>(dataStore, "strings", String.class, String.class, new LinkedHashMap<String, String>(), 16);
  300. MapWrapper<Integer, Integer> ints = new MapWrapper<Integer, Integer>(dataStore, "ints", Integer.class, Integer.class, new LinkedHashMap<Integer, Integer>(), 16);
  301. dataStore.start();
  302. ints.clear();
  303. strings.clear();
  304. InProcessChronicleSink chronicle2 = new InProcessChronicleSink(new IndexedChronicle(name2), "localhost", PORT);
  305. DataStore dataStore2 = new DataStore(chronicle2, ModelMode.READ_ONLY);
  306. MapWrapper<String, String> strings2 = new MapWrapper<String, String>(dataStore2, "strings", String.class, String.class, new LinkedHashMap<String, String>(), 16);
  307. MapWrapper<Integer, Integer> ints2 = new MapWrapper<Integer, Integer>(dataStore2, "ints", Integer.class, Integer.class, new LinkedHashMap<Integer, Integer>(), 16);
  308. final AtomicInteger sai = new AtomicInteger();
  309. MapListener<String, String> stringsListener = new AbstractMapListener<String, String>() {
  310. @Override
  311. public void update(String key, String oldValue, String newValue) {
  312. // System.out.println(key + " " + oldValue + " => " + newValue);
  313. sai.incrementAndGet();
  314. }
  315. };
  316. strings2.addListener(stringsListener);
  317. final AtomicInteger iai = new AtomicInteger();
  318. MapListener<Integer, Integer> intsListener = new AbstractMapListener<Integer, Integer>() {
  319. @Override
  320. public void update(Integer key, Integer oldValue, Integer newValue) {
  321. // System.out.println(key + " " + oldValue + " => " + newValue);
  322. iai.incrementAndGet();
  323. }
  324. };
  325. ints2.addListener(intsListener);
  326. dataStore2.start();
  327. Map<String, String> ssMap = new LinkedHashMap<String, String>();
  328. Map<Integer, Integer> iiMap = new LinkedHashMap<Integer, Integer>();
  329. int count = 2; // one clear per collection
  330. int collectionSize = 2000;
  331. for (int i = 0; i < collectionSize; i++) {
  332. iiMap.put(i, i);
  333. ssMap.put(Integer.toString(i), Integer.toString(i));
  334. }
  335. strings.putAll(ssMap);
  336. ints.putAll(iiMap);
  337. count += 2;
  338. Thread.sleep(100);
  339. // int timeout = 0;
  340. while (dataStore2.events() < count || ints2.size() < collectionSize) {
  341. // if (timeout++ % 10000 == 0)
  342. // System.out.println(dataStore2.events());
  343. Thread.sleep(1);
  344. }
  345. assertEquals(collectionSize, strings.size());
  346. assertEquals(collectionSize, strings2.size());
  347. assertEquals(collectionSize, ints.size());
  348. assertEquals(collectionSize, ints2.size());
  349. System.out.println("=== performing get test ===");
  350. int gets = 0;
  351. for (int j = 0; j < 10000; j++) {
  352. for (String s : ssMap.keySet()) {
  353. String s1 = strings.get(s);
  354. String s2 = strings2.get(s);
  355. if (s1 == null)
  356. assertNotNull(s1);
  357. if (!s1.equals(s2))
  358. assertEquals(s1, s2);
  359. }
  360. gets += ssMap.size();
  361. for (Integer i : iiMap.keySet()) {
  362. Integer i1 = ints.get(i);
  363. Integer i2 = ints2.get(i);
  364. if (i1 == null)
  365. assertNotNull(i1);
  366. if (!i1.equals(i2))
  367. assertEquals(i1, i2);
  368. }
  369. gets += iiMap.size();
  370. }
  371. chronicle.close();
  372. chronicle2.close();
  373. long end = System.nanoTime();
  374. System.out.printf("Average get time including startup, bootstrap and shutdown, took %.3f us average per key%n",
  375. (end - start) / gets / 1e3);
  376. }
  377. }