Package net.openhft.collections

Source Code of net.openhft.collections.SharedHashMapTest$IncrementRunnable

/*
* Copyright 2013 Peter Lawrey
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*         http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package net.openhft.collections;

import net.openhft.lang.model.DataValueClasses;
import net.openhft.lang.model.DataValueGenerator;
import net.openhft.lang.values.IntValue;
import net.openhft.lang.values.LongValue;
import net.openhft.lang.values.LongValue$$Native;
import org.junit.Ignore;
import org.junit.Test;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

import static net.openhft.collections.Alignment.*;
import static org.junit.Assert.*;

@SuppressWarnings({"unchecked", "ResultOfMethodCallIgnored"})
public class SharedHashMapTest {

    private StringBuilder sb = new StringBuilder();

    static void assertKeySet(Set<Integer> keySet, int[] expectedKeys) {
        Set<Integer> expectedSet = new HashSet<Integer>();
        for (int expectedKey : expectedKeys) {
            expectedSet.add(expectedKey);
        }

        assertEquals(expectedSet, keySet);
    }

    static void assertValues(Collection<CharSequence> values, CharSequence[] expectedValues) {
        List<String> expectedList = new ArrayList<String>();
        for (CharSequence expectedValue : expectedValues) {
            expectedList.add(expectedValue.toString());
        }
        Collections.sort(expectedList);

        List<String> actualList = new ArrayList<String>();
        for (CharSequence actualValue : values) {
            actualList.add(actualValue.toString());
        }
        Collections.sort(actualList);

        assertEquals(expectedList, actualList);
    }

    static void assertEntrySet(Set<Map.Entry<Integer, CharSequence>> entrySet, int[] expectedKeys, CharSequence[] expectedValues) {
        Set<Map.Entry<Integer, CharSequence>> expectedSet = new HashSet<Map.Entry<Integer, CharSequence>>();
        for (int i = 0; i < expectedKeys.length; i++) {
            expectedSet.add(new AbstractMap.SimpleEntry<Integer, CharSequence>(expectedKeys[i], expectedValues[i]));
        }

        assertEquals(expectedSet, entrySet);
    }

    static void assertMap(Map<Integer, CharSequence> map, int[] expectedKeys, CharSequence[] expectedValues) {
        assertEquals(expectedKeys.length, map.size());
        for (int i = 0; i < expectedKeys.length; i++) {
            assertEquals("On position " + i, expectedValues[i], map.get(expectedKeys[i]));
        }
    }

    @Test
    public void testRemoveWithKey() throws Exception {

        final SharedHashMap<CharSequence, CharSequence> map = new SharedHashMapBuilder()
                .minSegments(2).file(getPersistenceFile()).kClass(CharSequence.class).vClass(CharSequence.class).create();

        assertFalse(map.containsKey("key3"));
        map.put("key1", "one");
        map.put("key2", "two");
        assertEquals(2, map.size());

        assertTrue(map.containsKey("key1"));
        assertTrue(map.containsKey("key2"));
        assertFalse(map.containsKey("key3"));

        assertEquals("one", map.get("key1"));
        assertEquals("two", map.get("key2"));

        final CharSequence result = map.remove("key1");

        assertEquals(1, map.size());

        assertEquals("one", result);
        assertFalse(map.containsKey("key1"));

        assertEquals(null, map.get("key1"));
        assertEquals("two", map.get("key2"));
        assertFalse(map.containsKey("key3"));

        // lets add one more item for luck !
        map.put("key3", "three");
        assertEquals("three", map.get("key3"));
        assertTrue(map.containsKey("key3"));
        assertEquals(2, map.size());

        // and just for kicks we'll overwrite what we have
        map.put("key3", "overwritten");
        assertEquals("overwritten", map.get("key3"));
        assertTrue(map.containsKey("key3"));
        assertEquals(2, map.size());

        map.close();
    }


    @Test
    public void testSize() throws Exception {

        final SharedHashMap<CharSequence, CharSequence> map = new SharedHashMapBuilder()
                .minSegments(1024)
                .removeReturnsNull(true).file(getPersistenceFile()).kClass(CharSequence.class).vClass(CharSequence.class).create();


        for (int i = 1; i < 1024; i++) {
            map.put("key" + i, "value");
            assertEquals(i, map.size());
        }

        for (int i = 1023; i >= 1; ) {
            map.remove("key" + i);
            i--;
            assertEquals(i, map.size());
        }
        map.close();
    }

    @Test
    @Ignore //todo: fails on my machine
    public void testRemoveInteger() throws IOException {

        int count = 3000;
        final SharedHashMap<Object, Object> map = new SharedHashMapBuilder()
                .entrySize(count)
                .minSegments(2).file(getPersistenceFile()).kClass(Object.class).vClass(Object.class).create();


        for (int i = 1; i < count; i++) {
            map.put(i, i);
            assertEquals(i, map.size());
        }

        for (int i = count - 1; i >= 1; ) {
            Integer j = (Integer) map.put(i, i);
            assertEquals(i, j.intValue());
            Integer j2 = (Integer) map.remove(i);
            assertEquals(i, j2.intValue());
            i--;
            assertEquals(i, map.size());
        }
        map.close();
    }

    @Test
    public void testRemoveWithKeyAndRemoveReturnsNull() throws Exception {

        final SharedHashMap<CharSequence, CharSequence> map = new SharedHashMapBuilder()
                .minSegments(2)
                .removeReturnsNull(true).file(getPersistenceFile()).kClass(CharSequence.class).vClass(CharSequence.class).create();

        assertFalse(map.containsKey("key3"));
        map.put("key1", "one");
        map.put("key2", "two");
        assertEquals(2, map.size());

        assertTrue(map.containsKey("key1"));
        assertTrue(map.containsKey("key2"));
        assertFalse(map.containsKey("key3"));

        assertEquals("one", map.get("key1"));
        assertEquals("two", map.get("key2"));

        final CharSequence result = map.remove("key1");
        assertEquals(null, result);

        assertEquals(1, map.size());

        assertFalse(map.containsKey("key1"));

        assertEquals(null, map.get("key1"));
        assertEquals("two", map.get("key2"));
        assertFalse(map.containsKey("key3"));

        // lets add one more item for luck !
        map.put("key3", "three");
        assertEquals("three", map.get("key3"));
        assertTrue(map.containsKey("key3"));
        assertEquals(2, map.size());

        // and just for kicks we'll overwrite what we have
        map.put("key3", "overwritten");
        assertEquals("overwritten", map.get("key3"));
        assertTrue(map.containsKey("key3"));
        assertEquals(2, map.size());

        map.close();
    }


    @Test
    public void testReplaceWithKey() throws Exception {

        final SharedHashMap<CharSequence, CharSequence> map = new SharedHashMapBuilder()
                .minSegments(2).file(getPersistenceFile()).kClass(CharSequence.class).vClass(CharSequence.class).create();


        map.put("key1", "one");
        map.put("key2", "two");
        assertEquals(2, map.size());

        assertEquals("one", map.get("key1"));
        assertEquals("two", map.get("key2"));

        assertTrue(map.containsKey("key1"));
        assertTrue(map.containsKey("key2"));

        final CharSequence result = map.replace("key1", "newValue");

        assertEquals("one", result);
        assertTrue(map.containsKey("key1"));
        assertTrue(map.containsKey("key2"));
        assertEquals(2, map.size());

        assertEquals("newValue", map.get("key1"));
        assertEquals("two", map.get("key2"));

        assertTrue(map.containsKey("key1"));
        assertTrue(map.containsKey("key2"));
        assertFalse(map.containsKey("key3"));

        assertEquals(2, map.size());

        // let and one more item for luck !
        map.put("key3", "three");
        assertEquals(3, map.size());

        assertTrue(map.containsKey("key1"));
        assertTrue(map.containsKey("key2"));
        assertTrue(map.containsKey("key3"));
        assertEquals("three", map.get("key3"));

        // and just for kicks we'll overwrite what we have
        map.put("key3", "overwritten");
        assertEquals("overwritten", map.get("key3"));

        assertTrue(map.containsKey("key1"));
        assertTrue(map.containsKey("key2"));
        assertTrue(map.containsKey("key3"));

        final CharSequence result2 = map.replace("key2", "newValue");

        assertEquals("two", result2);
        assertEquals("newValue", map.get("key2"));

        final CharSequence result3 = map.replace("rubbish", "newValue");
        assertEquals(null, result3);

        assertFalse(map.containsKey("rubbish"));
        assertEquals(3, map.size());

        map.close();
    }


    @Test
    public void testReplaceWithKeyAnd2Params() throws Exception {

        final SharedHashMap<CharSequence, CharSequence> map = new SharedHashMapBuilder()
                .minSegments(2).file(getPersistenceFile()).kClass(CharSequence.class).vClass(CharSequence.class).create();

        map.put("key1", "one");
        map.put("key2", "two");

        assertEquals("one", map.get("key1"));
        assertEquals("two", map.get("key2"));

        final boolean result = map.replace("key1", "one", "newValue");

        assertEquals(true, result);

        assertEquals("newValue", map.get("key1"));
        assertEquals("two", map.get("key2"));

        // let and one more item for luck !
        map.put("key3", "three");
        assertEquals("three", map.get("key3"));

        // and just for kicks we'll overwrite what we have
        map.put("key3", "overwritten");
        assertEquals("overwritten", map.get("key3"));

        final boolean result2 = map.replace("key2", "two", "newValue2");

        assertEquals(true, result2);
        assertEquals("newValue2", map.get("key2"));

        final boolean result3 = map.replace("newKey", "", "newValue");
        assertEquals(false, result3);

        final boolean result4 = map.replace("key2", "newValue2", "newValue2");
        assertEquals(true, result4);

        map.close();
    }

    @Test
    public void testRemoveWithKeyAndValue() throws Exception {

        final SharedHashMap<CharSequence, CharSequence> map = new SharedHashMapBuilder()
                .minSegments(2).file(getPersistenceFile()).kClass(CharSequence.class).vClass(CharSequence.class).create();


        map.put("key1", "one");
        map.put("key2", "two");

        assertEquals("one", map.get("key1"));
        assertEquals("two", map.get("key2"));


        // a false remove
        final boolean wasRemoved1 = map.remove("key1", "three");

        assertFalse(wasRemoved1);


        assertEquals(null, map.get("key1"), "one");
        assertEquals("two", map.get("key2"), "two");

        map.put("key1", "one");


        final boolean wasRemoved2 = map.remove("key1", "three");
        assertFalse(wasRemoved2);

        // lets add one more item for luck !
        map.put("key3", "three");
        assertEquals("three", map.get("key3"));

        // and just for kicks we'll overwrite what we have
        map.put("key3", "overwritten");
        assertEquals("overwritten", map.get("key3"));

        map.close();
    }

    @Test
    public void testAcquireWithNullContainer() throws Exception {
        SharedHashMap<CharSequence, LongValue> map = getSharedMap(10 * 1000, 128, 24);
        map.acquireUsing("key", new LongValue$$Native());
        assertEquals(0, map.acquireUsing("key", null).getValue());

        map.close();
    }

    @Test
    public void testGetWithNullContainer() throws Exception {
        SharedHashMap<CharSequence, LongValue> map = getSharedMap(10 * 1000, 128, 24);
        map.acquireUsing("key", new LongValue$$Native());
        assertEquals(0, map.getUsing("key", null).getValue());

        map.close();
    }

    @Test
    public void testGetWithoutAcquireFirst() throws Exception {
        SharedHashMap<CharSequence, LongValue> map = getSharedMap(10 * 1000, 128, 24);
        assertNull(map.getUsing("key", new LongValue$$Native()));

        map.close();
    }

    @Test
    public void testAcquireAndGet() throws IOException, ClassNotFoundException,
            IllegalAccessException, InstantiationException {
        int entries = 100 * 1000;
        testAcquireAndGet(getSharedMap(entries, 128, 24, NO_ALIGNMENT), entries);
        testAcquireAndGet(getSharedMap(entries, 128, 24, OF_4_BYTES), entries);
        testAcquireAndGet(getSharedMap(entries, 128, 24, OF_8_BYTES), entries);
    }

    public void testAcquireAndGet(SharedHashMap<CharSequence, LongValue> map, int entries)
            throws IOException, ClassNotFoundException, IllegalAccessException,
            InstantiationException {
        LongValue value = new LongValue$$Native();
        LongValue value2 = new LongValue$$Native();
        LongValue value3 = new LongValue$$Native();

        for (int j = 1; j <= 3; j++) {
            for (int i = 0; i < entries; i++) {
                CharSequence userCS = getUserCharSequence(i);

                if (j > 1) {
                    assertNotNull(map.getUsing(userCS, value));
                } else {
                    map.acquireUsing(userCS, value);
                }
                assertEquals(j - 1, value.getValue());

                value.addAtomicValue(1);

                assertEquals(value2, map.acquireUsing(userCS, value2));
                assertEquals(j, value2.getValue());

                assertEquals(value3, map.getUsing(userCS, value3));
                assertEquals(j, value3.getValue());
            }
        }

        map.close();
    }

    @Test
    public void testAcquireFromMultipleThreads() throws Exception {
        int entries = 1000 * 1000;
        testAcquireFromMultipleThreads(getSharedMap(entries, 128, 24, NO_ALIGNMENT));
        testAcquireFromMultipleThreads(getSharedMap(entries, 128, 24, OF_4_BYTES));
        testAcquireFromMultipleThreads(getSharedMap(entries, 128, 24, OF_8_BYTES));
    }

    public void testAcquireFromMultipleThreads(SharedHashMap<CharSequence, LongValue> map)
            throws Exception {

        CharSequence key = getUserCharSequence(0);
        map.acquireUsing(key, new LongValue$$Native());

        int iterations = 1000;
        int noOfThreads = 10;
        CyclicBarrier barrier = new CyclicBarrier(noOfThreads);

        Thread[] threads = new Thread[noOfThreads];
        for (int t = 0; t < noOfThreads; t++) {
            threads[t] = new Thread(new IncrementRunnable(map, key, iterations, barrier));
            threads[t].start();
        }
        for (int t = 0; t < noOfThreads; t++) {
            threads[t].join();
        }

        assertEquals(noOfThreads * iterations, map.acquireUsing(key, new LongValue$$Native()).getValue());

        map.close();
    }

    private static final class IncrementRunnable implements Runnable {

        private final SharedHashMap<CharSequence, LongValue> map;

        private final CharSequence key;

        private final int iterations;

        private final CyclicBarrier barrier;

        private IncrementRunnable(SharedHashMap<CharSequence, LongValue> map, CharSequence key, int iterations, CyclicBarrier barrier) {
            this.map = map;
            this.key = key;
            this.iterations = iterations;
            this.barrier = barrier;
        }

        @Override
        public void run() {
            try {
                LongValue value = new LongValue$$Native();
                barrier.await();
                for (int i = 0; i < iterations; i++) {
                    map.acquireUsing(key, value);
                    value.addAtomicValue(1);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    // i7-3970X CPU @ 3.50GHz, hex core: -verbose:gc -Xmx64m
    // to tmpfs file system
    // 10M users, updated 12 times. Throughput 19.3 M ops/sec, no GC!
    // 50M users, updated 12 times. Throughput 19.8 M ops/sec, no GC!
    // 100M users, updated 12 times. Throughput 19.0M ops/sec, no GC!
    // 200M users, updated 12 times. Throughput 18.4 M ops/sec, no GC!
    // 400M users, updated 12 times. Throughput 18.4 M ops/sec, no GC!

    // to ext4 file system.
    // 10M users, updated 12 times. Throughput 17.7 M ops/sec, no GC!
    // 50M users, updated 12 times. Throughput 16.5 M ops/sec, no GC!
    // 100M users, updated 12 times. Throughput 15.9 M ops/sec, no GC!
    // 200M users, updated 12 times. Throughput 15.4 M ops/sec, no GC!
    // 400M users, updated 12 times. Throughput 7.8 M ops/sec, no GC!
    // 600M users, updated 12 times. Throughput 5.8 M ops/sec, no GC!

    // dual E5-2650v2 @ 2.6 GHz, 128 GB: -verbose:gc -Xmx32m
    // to tmpfs
    // TODO small GC on startup should be tidied up, [GC 9216K->1886K(31744K), 0.0036750 secs]
    // 10M users, updated 16 times. Throughput 33.0M ops/sec, VmPeak: 5373848 kB, VmRSS: 544252 kB
    // 50M users, updated 16 times. Throughput 31.2 M ops/sec, VmPeak: 9091804 kB, VmRSS: 3324732 kB
    // 250M users, updated 16 times. Throughput 30.0 M ops/sec, VmPeak:  24807836 kB, VmRSS: 14329112 kB
    // 1000M users, updated 16 times, Throughput 24.1 M ops/sec, VmPeak: 85312732 kB, VmRSS: 57165952 kB
    // 2500M users, updated 16 times, Throughput 23.5 M ops/sec, VmPeak: 189545308 kB, VmRSS: 126055868 kB

    // to ext4
    // 10M users, updated 16 times. Throughput 28.4 M ops/sec, VmPeak: 5438652 kB, VmRSS: 544624 kB
    // 50M users, updated 16 times. Throughput 28.2 M ops/sec, VmPeak: 9091804 kB, VmRSS: 9091804 kB
    // 250M users, updated 16 times. Throughput 26.1 M ops/sec, VmPeak:  24807836 kB, VmRSS: 24807836 kB
    // 1000M users, updated 16 times, Throughput 1.3 M ops/sec, TODO FIX this

    @Test
    public void testIntValue() {
        DataValueGenerator dvg = new DataValueGenerator();
        dvg.setDumpCode(true);
        dvg.acquireNativeClass(IntValue.class);
        dvg.acquireNativeClass(LongValue.class);
    }

    @Test
    @Ignore
    public void testAcquirePerf() throws IOException, ClassNotFoundException, IllegalAccessException, InstantiationException, InterruptedException, ExecutionException {
//        int runs = Integer.getInteger("runs", 10);
        for (int runs : new int[]{10, 50, 250, 500, 1000, 2500}) {
            final long entries = runs * 1000 * 1000L;
            final SharedHashMap<CharSequence, IntValue> map = getSharedStringIntMap(entries, 1024, 20);

            int procs = Runtime.getRuntime().availableProcessors();
            int threads = procs * 2; // runs > 100 ? procs / 2 : procs;
            int count = runs > 500 ? runs > 1200 ? 1 : 3 : 5;
            final int independence = 8; // Math.min(procs, runs > 500 ? 8 : 4);
            System.out.println("\nKey size: " + runs + " Million entries. ");
            for (int j = 0; j < count; j++) {
                long start = System.currentTimeMillis();
                ExecutorService es = Executors.newFixedThreadPool(procs);
                List<Future> futures = new ArrayList<Future>();
                for (int i = 0; i < threads; i++) {
                    final int t = i;
                    futures.add(es.submit(new Runnable() {
                        @Override
                        public void run() {
                            IntValue value = nativeIntValue();
                            StringBuilder sb = new StringBuilder();
                            long next = 50 * 1000 * 1000;
                            // use a factor to give up to 10 digit numbers.
                            int factor = Math.max(1, (int) ((10 * 1000 * 1000 * 1000L - 1) / entries));
                            for (long j = t % independence; j < entries + independence - 1; j += independence) {
                                sb.setLength(0);
                                sb.append("us:");
                                sb.append(j * factor);
                                map.acquireUsing(sb, value);
                                long n = value.addAtomicValue(1);
                                assert n > 0 && n < 1000 : "Counter corrupted " + n;
                                if (t == 0 && j >= next) {
                                    long size = map.longSize();
                                    if (size < 0) throw new AssertionError("size: " + size);
                                    System.out.println(j + ", size: " + size);
                                    next += 50 * 1000 * 1000;
                                }
                            }
                        }
                    }));
                }
                for (Future future : futures) {
                    future.get();
                }
                es.shutdown();
                es.awaitTermination(runs / 10 + 1, TimeUnit.MINUTES);
                long time = System.currentTimeMillis() - start;
                System.out.printf("Throughput %.1f M ops/sec%n", threads * entries / independence / 1000.0 / time);
            }
            printStatus();
            File file = map.file();
            map.close();
            file.delete();
        }
    }

    //  i7-3970X CPU @ 3.50GHz, hex core: -Xmx30g -verbose:gc
    // 10M users, updated 12 times. Throughput 16.2 M ops/sec, longest [Full GC 853669K->852546K(3239936K), 0.8255960 secs]
    // 50M users, updated 12 times. Throughput 13.3 M ops/sec,  longest [Full GC 5516214K->5511353K(13084544K), 3.5752970 secs]
    // 100M users, updated 12 times. Throughput 11.8 M ops/sec, longest [Full GC 11240703K->11233711K(19170432K), 5.8783010 secs]
    // 200M users, updated 12 times. Throughput 4.2 M ops/sec, longest [Full GC 25974721K->22897189K(27962048K), 21.7962600 secs]

    // dual E5-2650v2 @ 2.6 GHz, 128 GB: -verbose:gc -Xmx100g
    // 10M users, updated 16 times. Throughput 155.3 M ops/sec, VmPeak: 113291428 kB, VmRSS: 9272176 kB, [Full GC 1624336K->1616457K(7299072K), 2.5381610 secs]
    // 50M users, updated 16 times. Throughput 120.4 M ops/sec, VmPeak: 113291428 kB, VmRSS: 28436248 kB [Full GC 6545332K->6529639K(18179584K), 6.9053810 secs]
    // 250M users, updated 16 times. Throughput 114.1 M ops/sec, VmPeak: 113291428 kB, VmRSS: 76441464 kB  [Full GC 41349527K->41304543K(75585024K), 17.3217490 secs]
    // 1000M users, OutOfMemoryError.

    @Test
    @Ignore
    public void testCHMAcquirePerf() throws IOException, ClassNotFoundException, IllegalAccessException, InstantiationException, InterruptedException {
        for (int runs : new int[]{10, 50, 250, 1000, 2500}) {
            System.out.println("Testing " + runs + " million entries");
            final long entries = runs * 1000 * 1000L;
            final ConcurrentMap<String, AtomicInteger> map = new ConcurrentHashMap<String, AtomicInteger>((int) (entries * 5 / 4), 1.0f, 1024);

            int procs = Runtime.getRuntime().availableProcessors();
            int threads = procs * 2;
            int count = runs > 500 ? runs > 1200 ? 1 : 2 : 3;
            final int independence = Math.min(procs, runs > 500 ? 8 : 4);
            for (int j = 0; j < count; j++) {
                long start = System.currentTimeMillis();
                ExecutorService es = Executors.newFixedThreadPool(procs);
                for (int i = 0; i < threads; i++) {
                    final int t = i;
                    es.submit(new Runnable() {
                        @Override
                        public void run() {
                            StringBuilder sb = new StringBuilder();
                            int next = 50 * 1000 * 1000;
                            // use a factor to give up to 10 digit numbers.
                            int factor = Math.max(1, (int) ((10 * 1000 * 1000 * 1000L - 1) / entries));
                            for (long i = t % independence; i < entries; i += independence) {
                                sb.setLength(0);
                                sb.append("u:");
                                sb.append(i * factor);
                                String key = sb.toString();
                                AtomicInteger count = map.get(key);
                                if (count == null) {
                                    map.put(key, new AtomicInteger());
                                    count = map.get(key);
                                }
                                count.getAndIncrement();
                                if (t == 0 && i == next) {
                                    System.out.println(i);
                                    next += 50 * 1000 * 1000;
                                }
                            }
                        }
                    });
                }
                es.shutdown();
                es.awaitTermination(10, TimeUnit.MINUTES);
                printStatus();
                long time = System.currentTimeMillis() - start;
                System.out.printf("Throughput %.1f M ops/sec%n", threads * entries / 1000.0 / time);
            }
        }
    }

    public static LongValue nativeLongValue() {
        return new LongValue$$Native();
    }

    public static IntValue nativeIntValue() {
        return DataValueClasses.newDirectReference(IntValue.class);
//        return new LongValue$$Native();
    }

    private CharSequence getUserCharSequence(int i) {
        sb.setLength(0);
        sb.append("u:");
        sb.append(i * 9876); // test 10 digit user numbers.
        return sb;
    }

    static long count = 0;

    static File getPersistenceFile() {
        String TMP = System.getProperty("java.io.tmpdir");
        File file = new File(TMP + "/shm-test" + System.nanoTime() + count++);
        file.deleteOnExit();
        return file;
    }

    private static SharedHashMap<CharSequence, LongValue> getSharedMap(
            long entries, int segments, int entrySize) throws IOException {
        return getSharedMap(entries, segments, entrySize, OF_4_BYTES);
    }

    private static SharedHashMap<CharSequence, LongValue> getSharedMap(
            long entries, int segments, int entrySize, Alignment alignment)
            throws IOException {
        return new SharedHashMapBuilder()
                .entries(entries)
                .minSegments(segments)
                .entrySize(entrySize)
                .entryAndValueAlignment(alignment)
                .generatedValueType(true).file(getPersistenceFile()).kClass(CharSequence.class).vClass(LongValue.class).create();
    }

    private static SharedHashMap<CharSequence, IntValue> getSharedStringIntMap(long entries, int segments, int entrySize) throws IOException {
        return new SharedHashMapBuilder()
                .entries(entries)
                .minSegments(segments)
                .entrySize(entrySize)
                .generatedValueType(true)
                .putReturnsNull(true).file(getPersistenceFile()).kClass(CharSequence.class).vClass(IntValue.class).create();
    }

    private static void printStatus() {
        if (!new File("/proc/self/status").exists()) return;
        try {
            BufferedReader br = new BufferedReader(new FileReader("/proc/self/status"));
            for (String line; (line = br.readLine()) != null; )
                if (line.startsWith("Vm"))
                    System.out.print(line.replaceAll("  +", " ") + ", ");
            System.out.println();
            br.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Test
    public void testPutAndRemove() throws IOException, ClassNotFoundException, IllegalAccessException, InstantiationException {
        String TMP = System.getProperty("java.io.tmpdir");
        File file = new File(TMP + "/shm-remove-test");
        file.delete();
        file.deleteOnExit();
        int entries = 100 * 1000;
        SharedHashMap<CharSequence, CharSequence> map =
                new SharedHashMapBuilder()
                        .entries(entries)
                        .minSegments(16)
                        .entrySize(32)
                        .putReturnsNull(true)
                        .removeReturnsNull(true).file(file).kClass(CharSequence.class).vClass(CharSequence.class).create();
        StringBuilder key = new StringBuilder();
        StringBuilder value = new StringBuilder();
        StringBuilder value2 = new StringBuilder();
        for (int j = 1; j <= 3; j++) {
            for (int i = 0; i < entries; i++) {
                key.setLength(0);
                key.append("user:").append(i);
                value.setLength(0);
                value.append("value:").append(i);
//                System.out.println(key);
                assertNull(map.getUsing(key, value));
                assertNull(map.put(key, value));
                assertNotNull(map.getUsing(key, value2));
                assertEquals(value.toString(), value2.toString());
                assertNull(map.remove(key));
                assertNull(map.getUsing(key, value));
            }
        }

        map.close();
    }

    @Test
    public void mapRemoveReflectedInViews() throws IOException {
        SharedHashMap<Integer, CharSequence> map = getViewTestMap(3);
        Set<Map.Entry<Integer, CharSequence>> entrySet = map.entrySet();
        Set<Integer> keySet = map.keySet();
        Collection<CharSequence> values = map.values();

        map.remove(2);
        assertMap(map, new int[]{1, 3}, new CharSequence[]{"1", "3"});
        assertEntrySet(entrySet, new int[]{1, 3}, new CharSequence[]{"1", "3"});
        assertEntrySet(map.entrySet(), new int[]{1, 3}, new CharSequence[]{"1", "3"});
        assertKeySet(keySet, new int[]{1, 3});
        assertKeySet(map.keySet(), new int[]{1, 3});
        assertValues(values, new CharSequence[]{"1", "3"});
        assertValues(map.values(), new CharSequence[]{"1", "3"});

        map.close();
    }

    @Test
    public void mapPutReflectedInViews() throws IOException {
        SharedHashMap<Integer, CharSequence> map = getViewTestMap(3);
        Set<Map.Entry<Integer, CharSequence>> entrySet = map.entrySet();
        Set<Integer> keySet = map.keySet();
        Collection<CharSequence> values = map.values();

        map.put(4, "4");
        assertMap(map, new int[]{4, 2, 3, 1}, new CharSequence[]{"4", "2", "3", "1"});
        assertEntrySet(entrySet, new int[]{4, 2, 3, 1}, new CharSequence[]{"4", "2", "3", "1"});
        assertEntrySet(map.entrySet(), new int[]{4, 2, 3, 1}, new CharSequence[]{"4", "2", "3", "1"});
        assertKeySet(keySet, new int[]{4, 2, 3, 1});
        assertKeySet(map.keySet(), new int[]{4, 2, 3, 1});
        assertValues(values, new CharSequence[]{"2", "1", "4", "3"});
        assertValues(map.values(), new CharSequence[]{"2", "1", "4", "3"});

        map.close();
    }

    @Test
    public void entrySetRemoveReflectedInMapAndOtherViews() throws IOException {
        SharedHashMap<Integer, CharSequence> map = getViewTestMap(3);
        Set<Map.Entry<Integer, CharSequence>> entrySet = map.entrySet();
        Set<Integer> keySet = map.keySet();
        Collection<CharSequence> values = map.values();

        entrySet.remove(new AbstractMap.SimpleEntry<Integer, CharSequence>(2, "2"));
        assertMap(map, new int[]{1, 3}, new CharSequence[]{"1", "3"});
        assertEntrySet(entrySet, new int[]{1, 3}, new CharSequence[]{"1", "3"});
        assertKeySet(keySet, new int[]{1, 3});
        assertValues(values, new CharSequence[]{"1", "3"});

        map.close();
    }

    @Test
    public void keySetRemoveReflectedInMapAndOtherViews() throws IOException {
        SharedHashMap<Integer, CharSequence> map = getViewTestMap(3);
        Set<Map.Entry<Integer, CharSequence>> entrySet = map.entrySet();
        Set<Integer> keySet = map.keySet();
        Collection<CharSequence> values = map.values();

        keySet.remove(2);
        assertMap(map, new int[]{1, 3}, new CharSequence[]{"1", "3"});
        assertEntrySet(entrySet, new int[]{1, 3}, new CharSequence[]{"1", "3"});
        assertKeySet(keySet, new int[]{1, 3});
        assertValues(values, new CharSequence[]{"1", "3"});

        map.close();
    }

    @Test
    public void valuesRemoveReflectedInMap() throws IOException {
        SharedHashMap<Integer, CharSequence> map = getViewTestMap(3);
        Set<Map.Entry<Integer, CharSequence>> entrySet = map.entrySet();
        Set<Integer> keySet = map.keySet();
        Collection<CharSequence> values = map.values();

        values.remove("2");
        assertMap(map, new int[]{1, 3}, new CharSequence[]{"1", "3"});
        assertEntrySet(entrySet, new int[]{1, 3}, new CharSequence[]{"1", "3"});
        assertKeySet(keySet, new int[]{1, 3});
        assertValues(values, new CharSequence[]{"1", "3"});

        map.close();
    }


    @Test
    public void entrySetIteratorRemoveReflectedInMapAndOtherViews() throws IOException {
        SharedHashMap<Integer, CharSequence> map = getViewTestMap(3);
        Set<Map.Entry<Integer, CharSequence>> entrySet = map.entrySet();
        Set<Integer> keySet = map.keySet();
        Collection<CharSequence> values = map.values();

        Iterator<Map.Entry<Integer, CharSequence>> entryIterator = entrySet.iterator();
        Map.Entry<Integer, CharSequence> next1 = entryIterator.next();
        Map.Entry<Integer, CharSequence> next2 = entryIterator.next();
        entryIterator.remove();
        assertMap(map, new int[]{2, 3}, new CharSequence[]{"2", "3"});
        assertEntrySet(entrySet, new int[]{2, 3}, new CharSequence[]{"2", "3"});
        assertKeySet(keySet, new int[]{2, 3});
        assertValues(values, new CharSequence[]{"2", "3"});

        map.close();
    }

    @Test
    public void keySetIteratorRemoveReflectedInMapAndOtherViews() throws IOException {
        SharedHashMap<Integer, CharSequence> map = getViewTestMap(3);
        Set<Map.Entry<Integer, CharSequence>> entrySet = map.entrySet();
        Set<Integer> keySet = map.keySet();
        Collection<CharSequence> values = map.values();

        Iterator<Integer> keyIterator = keySet.iterator();
        keyIterator.next();
        keyIterator.next();
        keyIterator.remove();
        assertMap(map, new int[]{2, 3}, new CharSequence[]{"2", "3"});
        assertEntrySet(entrySet, new int[]{2, 3}, new CharSequence[]{"2", "3"});
        assertKeySet(keySet, new int[]{2, 3});
        assertValues(values, new CharSequence[]{"2", "3"});

        map.close();
    }

    @Test
    public void valuesIteratorRemoveReflectedInMapAndOtherViews() throws IOException {
        SharedHashMap<Integer, CharSequence> map = getViewTestMap(3);
        Set<Map.Entry<Integer, CharSequence>> entrySet = map.entrySet();
        Set<Integer> keySet = map.keySet();
        Collection<CharSequence> values = map.values();

        Iterator<CharSequence> valueIterator = values.iterator();
        valueIterator.next();
        valueIterator.next();
        valueIterator.remove();
        assertMap(map, new int[]{2, 3}, new CharSequence[]{"2", "3"});
        assertEntrySet(entrySet, new int[]{2, 3}, new CharSequence[]{"2", "3"});
        assertKeySet(keySet, new int[]{2, 3});
        assertValues(values, new CharSequence[]{"2", "3"});

        map.close();
    }

    @Test
    public void entrySetRemoveAllReflectedInMapAndOtherViews() throws IOException {
        SharedHashMap<Integer, CharSequence> map = getViewTestMap(3);
        Set<Map.Entry<Integer, CharSequence>> entrySet = map.entrySet();
        Set<Integer> keySet = map.keySet();
        Collection<CharSequence> values = map.values();

        entrySet.removeAll(
                Arrays.asList(
                        new AbstractMap.SimpleEntry<Integer, CharSequence>(1, "1"),
                        new AbstractMap.SimpleEntry<Integer, CharSequence>(2, "2")
                )
        );
        assertMap(map, new int[]{3}, new CharSequence[]{"3"});
        assertEntrySet(entrySet, new int[]{3}, new CharSequence[]{"3"});
        assertKeySet(keySet, new int[]{3});
        assertValues(values, new CharSequence[]{"3"});

        map.close();
    }

    @Test
    public void keySetRemoveAllReflectedInMapAndOtherViews() throws IOException {
        SharedHashMap<Integer, CharSequence> map = getViewTestMap(3);
        Set<Map.Entry<Integer, CharSequence>> entrySet = map.entrySet();
        Set<Integer> keySet = map.keySet();
        Collection<CharSequence> values = map.values();

        keySet.removeAll(Arrays.asList(1, 2));
        assertMap(map, new int[]{3}, new CharSequence[]{"3"});
        assertEntrySet(entrySet, new int[]{3}, new CharSequence[]{"3"});
        assertKeySet(keySet, new int[]{3});
        assertValues(values, new CharSequence[]{"3"});

        map.close();
    }








    @Test
    public void valuesRemoveAllReflectedInMapAndOtherViews() throws IOException {
        SharedHashMap<Integer, CharSequence> map = getViewTestMap(3);
        Set<Map.Entry<Integer, CharSequence>> entrySet = map.entrySet();
        Set<Integer> keySet = map.keySet();
        Collection<CharSequence> values = map.values();

        values.removeAll(Arrays.asList("1", "2"));
        assertMap(map, new int[]{3}, new CharSequence[]{"3"});
        assertEntrySet(entrySet, new int[]{3}, new CharSequence[]{"3"});
        assertKeySet(keySet, new int[]{3});
        assertValues(values, new CharSequence[]{"3"});

        map.close();
    }

    @Test
    public void entrySetRetainAllReflectedInMapAndOtherViews() throws IOException {
        SharedHashMap<Integer, CharSequence> map = getViewTestMap(3);
        Set<Map.Entry<Integer, CharSequence>> entrySet = map.entrySet();
        Set<Integer> keySet = map.keySet();
        Collection<CharSequence> values = map.values();

        entrySet.retainAll(
                Arrays.asList(
                        new AbstractMap.SimpleEntry<Integer, CharSequence>(1, "1"),
                        new AbstractMap.SimpleEntry<Integer, CharSequence>(2, "2")
                )
        );
        assertMap(map, new int[]{2, 1}, new CharSequence[]{"2", "1"});
        assertEntrySet(entrySet, new int[]{2, 1}, new CharSequence[]{"2", "1"});
        assertKeySet(keySet, new int[]{2, 1});
        assertValues(values, new CharSequence[]{"2", "1"});

        map.close();
    }

    @Test
    public void keySetRetainAllReflectedInMapAndOtherViews() throws IOException {
        SharedHashMap<Integer, CharSequence> map = getViewTestMap(3);
        Set<Map.Entry<Integer, CharSequence>> entrySet = map.entrySet();
        Set<Integer> keySet = map.keySet();
        Collection<CharSequence> values = map.values();

        keySet.retainAll(Arrays.asList(1, 2));
        assertMap(map, new int[]{2, 1}, new CharSequence[]{"2", "1"});
        assertEntrySet(entrySet, new int[]{2, 1}, new CharSequence[]{"2", "1"});
        assertKeySet(keySet, new int[]{2, 1});
        assertValues(values, new CharSequence[]{"2", "1"});

        map.close();
    }

    @Test
    public void valuesRetainAllReflectedInMapAndOtherViews() throws IOException {
        SharedHashMap<Integer, CharSequence> map = getViewTestMap(3);
        Set<Map.Entry<Integer, CharSequence>> entrySet = map.entrySet();
        Set<Integer> keySet = map.keySet();
        Collection<CharSequence> values = map.values();

        values.retainAll(Arrays.asList("1", "2"));
        assertMap(map, new int[]{2, 1}, new CharSequence[]{"2", "1"});
        assertEntrySet(entrySet, new int[]{2, 1}, new CharSequence[]{"2", "1"});
        assertKeySet(keySet, new int[]{2, 1});
        assertValues(values, new CharSequence[]{"2", "1"});

        map.close();
    }

    @Test
    public void entrySetClearReflectedInMapAndOtherViews() throws IOException {
        SharedHashMap<Integer, CharSequence> map = getViewTestMap(3);
        Set<Map.Entry<Integer, CharSequence>> entrySet = map.entrySet();
        Set<Integer> keySet = map.keySet();
        Collection<CharSequence> values = map.values();

        entrySet.clear();
        org.junit.Assert.assertTrue(map.isEmpty());
        org.junit.Assert.assertTrue(entrySet.isEmpty());
        org.junit.Assert.assertTrue(keySet.isEmpty());
        org.junit.Assert.assertTrue(values.isEmpty());

        map.close();
    }

    @Test
    public void keySetClearReflectedInMapAndOtherViews() throws IOException {
        SharedHashMap<Integer, CharSequence> map = getViewTestMap(3);
        Set<Map.Entry<Integer, CharSequence>> entrySet = map.entrySet();
        Set<Integer> keySet = map.keySet();
        Collection<CharSequence> values = map.values();

        keySet.clear();
        org.junit.Assert.assertTrue(map.isEmpty());
        org.junit.Assert.assertTrue(entrySet.isEmpty());
        org.junit.Assert.assertTrue(keySet.isEmpty());
        org.junit.Assert.assertTrue(values.isEmpty());

        map.close();
    }

    @Test
    public void valuesClearReflectedInMapAndOtherViews() throws IOException {
        SharedHashMap<Integer, CharSequence> map = getViewTestMap(3);
        Set<Map.Entry<Integer, CharSequence>> entrySet = map.entrySet();
        Set<Integer> keySet = map.keySet();
        Collection<CharSequence> values = map.values();

        values.clear();
        org.junit.Assert.assertTrue(map.isEmpty());
        org.junit.Assert.assertTrue(entrySet.isEmpty());
        org.junit.Assert.assertTrue(keySet.isEmpty());
        org.junit.Assert.assertTrue(values.isEmpty());

        map.close();
    }

    @Test
    public void clearMapViaEntryIteratorRemoves() throws IOException {
        int noOfElements = 16 * 1024;
        SharedHashMap<Integer, CharSequence> map = getViewTestMap(noOfElements);

        int sum = 0;
        for (Iterator it = map.entrySet().iterator(); it.hasNext(); ) {
            it.next();
            it.remove();
            ++sum;
        }
        map.close();

        assertEquals(noOfElements, sum);
    }

    @Test
    public void clearMapViaKeyIteratorRemoves() throws IOException {
        int noOfElements = 16 * 1024;
        SharedHashMap<Integer, CharSequence> map = getViewTestMap(noOfElements);

        Set<Integer> keys = new HashSet<Integer>();
        for (int i = 1; i <= noOfElements; i++) {
            keys.add(i);
        }

        int sum = 0;
        for (Iterator it = map.keySet().iterator(); it.hasNext(); ) {
            Object key = it.next();
            keys.remove(key);
            it.remove();
            ++sum;
        }
        map.close();

        assertEquals(noOfElements, sum);
    }


    @Test(expected = IllegalStateException.class)
    public void testRemoveWhenNextIsNotCalled() throws IOException {

        SharedHashMap<Integer, CharSequence> map = getViewTestMap(2);

        Iterator<Integer> iterator = map.keySet().iterator();
        iterator.remove();
    }

    @Test
    public void clearMapViaValueIteratorRemoves() throws IOException {
        int noOfElements = 16 * 1024;
        SharedHashMap<Integer, CharSequence> map = getViewTestMap(noOfElements);

        int sum = 0;
        for (Iterator it = map.values().iterator(); it.hasNext(); ) {
            it.next();
            it.remove();
            ++sum;
        }
        map.close();

        assertEquals(noOfElements, sum);
    }

    @Test
    public void entrySetValueReflectedInMapAndOtherViews() throws IOException {
        SharedHashMap<Integer, CharSequence> map = getViewTestMap(0);

        map.put(1, "A");
        Set<Map.Entry<Integer, CharSequence>> entrySet = map.entrySet();
        Set<Integer> keySet = map.keySet();
        Collection<CharSequence> values = map.values();

        assertMap(map, new int[]{1}, new CharSequence[]{"A"});
        assertEntrySet(entrySet, new int[]{1}, new CharSequence[]{"A"});
        assertKeySet(keySet, new int[]{1});
        assertValues(values, new String[]{"A"});

        entrySet.iterator().next().setValue("B");
        assertMap(map, new int[]{1}, new CharSequence[]{"B"});
        assertEntrySet(entrySet, new int[]{1}, new CharSequence[]{"B"});
        assertEntrySet(map.entrySet(), new int[]{1}, new CharSequence[]{"B"});
        assertKeySet(keySet, new int[]{1});
        assertKeySet(map.keySet(), new int[]{1});
        assertValues(values, new String[]{"B"});
        assertValues(map.values(), new String[]{"B"});

        map.close();
    }

    private SharedHashMap<Integer, CharSequence> getViewTestMap(int noOfElements) throws IOException {
        String TMP = System.getProperty("java.io.tmpdir");
        File file = new File(TMP + "/shm-remove-test");
        file.delete();
        file.deleteOnExit();
        int entries = 100 * 1000;
        SharedHashMap<Integer, CharSequence> map =
                new SharedHashMapBuilder()
                        .entries(entries)
                        .minSegments(16)
                        .entrySize(32)
                        .putReturnsNull(true)
                        .removeReturnsNull(true).file(file).kClass(Integer.class).vClass(CharSequence.class).create();

        int[] expectedKeys = new int[noOfElements];
        String[] expectedValues = new String[noOfElements];
        for (int i = 1; i <= noOfElements; i++) {
            String value = "" + i;
            map.put(i, value);
            expectedKeys[i - 1] = i;
            expectedValues[i - 1] = value;
        }

        return map;
    }

    @Test
    public void testOversizeEntriesPutRemoveReplace() throws IOException {
        SharedHashMapBuilder builder = new SharedHashMapBuilder()
                .entries(2)
                .minSegments(1)
                .entrySize(10);
        builder.entryAndValueAlignment(NO_ALIGNMENT);
        testOversizeEntriesPutRemoveReplace(
                (VanillaSharedHashMap<CharSequence, CharSequence>)
                        builder.file(getPersistenceFile()).kClass(CharSequence.class).vClass(CharSequence.class).create()
        );
        builder.entryAndValueAlignment(Alignment.OF_4_BYTES);
        testOversizeEntriesPutRemoveReplace(
                (VanillaSharedHashMap<CharSequence, CharSequence>)
                        builder.file(getPersistenceFile()).kClass(CharSequence.class).vClass(CharSequence.class).create()
        );
        builder.entryAndValueAlignment(OF_8_BYTES);
        testOversizeEntriesPutRemoveReplace(
                (VanillaSharedHashMap<CharSequence, CharSequence>)
                        builder.file(getPersistenceFile()).kClass(CharSequence.class).vClass(CharSequence.class).create()
        );
    }

    public void testOversizeEntriesPutRemoveReplace(
            VanillaSharedHashMap<CharSequence, CharSequence> map) {
        String key = "k";
        String oversizedKey = "oversized key";
        String value = "v";
        String oversizedValue = "oversized value";

        map.put(key, oversizedValue);
        assertEquals(oversizedValue, map.get(key));
        map.replace(key, value);
        map.checkConsistency();
        assertEquals(value, map.get(key));
        map.replace(key, oversizedValue);
        map.checkConsistency();
        assertEquals(oversizedValue, map.get(key));

        map.put(oversizedKey, value);
        map.checkConsistency();
        assertEquals(value, map.get(oversizedKey));
        map.replace(oversizedKey, oversizedValue);
        map.checkConsistency();
        assertEquals(oversizedValue, map.get(oversizedKey));
        map.remove(oversizedKey);
        map.checkConsistency();
        assertEquals(null, map.get(oversizedKey));
        map.put(oversizedKey, oversizedValue);
        map.checkConsistency();
        assertEquals(oversizedValue, map.get(oversizedKey));
        map.replace(oversizedKey, oversizedValue, value);
        map.checkConsistency();
        assertEquals(value, map.get(oversizedKey));

        assertEquals(value, map.remove(oversizedKey));
        map.checkConsistency();
        assertEquals(oversizedValue, map.remove(key));
        map.checkConsistency();

        map.close();
    }

    @Test
    public void equalsTest() throws IOException {
        final SharedHashMap<Integer, String> map1 = new SharedHashMapBuilder().file(getPersistenceFile()).kClass(Integer.class).vClass(String.class).create();

        map1.put(1, "one");
        map1.put(2, "two");

        final SharedHashMap<Integer, String> map2 = new SharedHashMapBuilder().file(getPersistenceFile()).kClass(Integer.class).vClass(String.class).create();

        map2.put(1, "one");
        map2.put(2, "two");

        assertEquals(map1, map2);
    }
}
TOP

Related Classes of net.openhft.collections.SharedHashMapTest$IncrementRunnable

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.