From 6045d017e601567aba5bdee52f60833c956e40af Mon Sep 17 00:00:00 2001 From: leventov Date: Sat, 5 Dec 2015 04:07:57 +0300 Subject: [PATCH] Added example of Chronicle Map diagnostics using the API --- README.md | 17 +++++++ src/test/java/eg/MapDiagnostics.java | 35 ++++++++++++++ src/test/java/eg/WordCountTest.java | 69 ++++++++++++++++++++++++++++ 3 files changed, 121 insertions(+) create mode 100644 src/test/java/eg/MapDiagnostics.java create mode 100644 src/test/java/eg/WordCountTest.java diff --git a/README.md b/README.md index 083747133..f07c31604 100644 --- a/README.md +++ b/README.md @@ -126,6 +126,7 @@ Not supported out of the box in open-source version, but could be added in ad-ho - [Example - BiMap](#example---bimap) - [Example - CRDT values for replicated Chronicle Maps - Grow-only set]( #example---crdt-values-for-replicated-chronicle-maps---grow-only-set) + - [Example - Monitor Chronicle Map statistics](#example---monitor-chronicle-map-statistics) ### Difference between Chronicle Map 2 and 3 @@ -1056,6 +1057,8 @@ Combined, interception SPI interfaces and `ChronicleMap.queryContext()` API are - Perform multi-key operations on a single `ChronicleMap` correctly in concurrent environment, by acquiring locks on all keys before updating the entries - Define own replication/reconciliation logic for distributed Chronicle Maps + - Dump statistics of a Chronicle Map data structure -- each segment's load, size in bytes of each + entry, etc. #### Example - Simple logging @@ -1408,3 +1411,17 @@ ChronicleMap> map1 = ChronicleMapBuilder .name("map1") .create(); ``` + +#### Example - Monitor Chronicle Map Statistics + +```java + public static void printMapStats(ChronicleMap map) { + for (int i = 0; i < map.segments(); i++) { + try (MapSegmentContext c = map.segmentContext(i)) { + System.out.printf("segment %d contains %d entries\n", i, c.size()); + c.forEachSegmentEntry(e -> System.out.printf("%s, %d bytes -> %s, %d bytes\n", + e.key(), e.key().size(), e.value(), e.value().size())); + } + } + } +``` diff --git a/src/test/java/eg/MapDiagnostics.java b/src/test/java/eg/MapDiagnostics.java new file mode 100644 index 000000000..3f3dc7de5 --- /dev/null +++ b/src/test/java/eg/MapDiagnostics.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2015 higherfrequencytrading.com + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package eg; + +import net.openhft.chronicle.map.ChronicleMap; +import net.openhft.chronicle.map.MapSegmentContext; + +public final class MapDiagnostics { + + public static void printMapStats(ChronicleMap map) { + for (int i = 0; i < map.segments(); i++) { + try (MapSegmentContext c = map.segmentContext(i)) { + System.out.printf("segment %d contains %d entries\n", i, c.size()); + c.forEachSegmentEntry(e -> System.out.printf("%s, %d bytes -> %s, %d bytes\n", + e.key(), e.key().size(), e.value(), e.value().size())); + } + } + } + + private MapDiagnostics() {} +} diff --git a/src/test/java/eg/WordCountTest.java b/src/test/java/eg/WordCountTest.java new file mode 100644 index 000000000..25bf53b3a --- /dev/null +++ b/src/test/java/eg/WordCountTest.java @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2015 higherfrequencytrading.com + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package eg; + +import com.google.common.io.ByteStreams; +import net.openhft.chronicle.core.io.Closeable; +import net.openhft.chronicle.core.values.IntValue; +import net.openhft.chronicle.map.ChronicleMap; +import net.openhft.chronicle.values.Values; +import org.junit.Test; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Arrays; +import java.util.zip.GZIPInputStream; + +import static java.nio.charset.StandardCharsets.UTF_8; + +public class WordCountTest { + + static String[] words; + static int expectedSize; + static { + try { + // english version of war and peace -> ascii + ClassLoader cl = Thread.currentThread().getContextClassLoader(); + InputStream zippedIS = cl.getResourceAsStream("war_and_peace.txt.gz"); + GZIPInputStream binaryIS = new GZIPInputStream(zippedIS); + String fullText = + new String(ByteStreams.toByteArray(binaryIS), UTF_8); + words = fullText.split("\\s+"); + expectedSize = (int) Arrays.stream(words).distinct().count(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + @Test + public void wordCountTest() throws IOException { + try (ChronicleMap map = ChronicleMap + .of(CharSequence.class, IntValue.class) + .averageKeySize(7) // average word is 7 ascii bytes long (text in english) + .entries(expectedSize) + .create()) { + IntValue v = Values.newNativeReference(IntValue.class); + for (String word : words) { + try (Closeable ignored = map.acquireContext(word, v)) { + v.addValue(1); + } + } + MapDiagnostics.printMapStats(map); + } + } +} +