src/jdk.jfr/share/classes/jdk/jfr/internal/util/PerfectHashMap.java
author mgronlun
Fri, 17 May 2019 18:03:14 +0200
branchJEP-349-branch
changeset 57361 53dccc90a5be
permissions -rw-r--r--
Preview-addendum
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
57361
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
     1
package jdk.jfr.internal.util;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
     2
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
     3
import java.util.Arrays;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
     4
import java.util.HashMap;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
     5
import java.util.Map;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
     6
import java.util.Objects;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
     7
import java.util.function.BiConsumer;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
     8
import java.util.function.Consumer;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
     9
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    10
public class PerfectHashMap<V> {
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    11
    private static final long COLLISION_SHIFT = 63;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    12
    private static final long COLLISION_BIT = 1L << COLLISION_SHIFT;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    13
    private static final long COLLISION_MASK = COLLISION_BIT - 1;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    14
    private static final int MAX_REMAP_ATTEMPTS = 100000;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    15
    private static final int  MAX_ATTEMPS_BEFORE_RESIZE = 100;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    16
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    17
    static final long W = 64L;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    18
    static class LinkedValue<V> {
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    19
        final V value;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    20
        long next;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    21
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    22
        LinkedValue(V value) {
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    23
            this.value = value;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    24
            this.next = 0;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    25
        }
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    26
    }
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    27
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    28
    private UniversalHashFamily hashFamily = new UniversalHashFamily();
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    29
    private PrimitiveHashMap<LinkedValue<V>> loadMap;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    30
    private Object[] valueTable;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    31
    private long[] routeTable;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    32
    private long shift;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    33
    private long shiftMask;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    34
    private int tableLengthMask;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    35
    private long primaryHashFunction = 0;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    36
    private int collisions = 0;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    37
    private int retries = 0;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    38
    private int sizeFactor = 1;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    39
    private boolean minimal;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    40
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    41
    public V get(long key) {
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    42
        LinkedValue<V> v = loadMap.get(key);
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    43
        return v != null ? v.value : null;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    44
    }
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    45
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    46
    public V put(long key, V value) {
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    47
        LinkedValue<V> existing = loadMap.put(key, new LinkedValue<V>(value));
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    48
        return existing != null ? existing.value : null;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    49
    }
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    50
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    51
    public void forEach(BiConsumer<? super Long, ? super V> action) {
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    52
        //loadMap.forEach(PerfectHashMap<V>::callback);
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    53
    }
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    54
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    55
    public final void forEach(Consumer<? super V> action) {
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    56
        //loadMap.forEach(action);
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    57
    }
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    58
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    59
    public final long[] keys() {
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    60
        return loadMap.keys();
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    61
    }
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    62
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    63
    static class Log2 {
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    64
        private static final int MAX_SIZE_EXPONENT = 32;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    65
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    66
        static long log2base10(long exponent) {
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    67
            return 1L << exponent;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    68
        }
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    69
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    70
        static int log2(int value) {
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    71
            int i = 0;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    72
            int lastMultiple = 0;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    73
            while (i < MAX_SIZE_EXPONENT) {
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    74
                int multiple = (int)log2base10(i);
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    75
                if ((value & multiple) != 0) {
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    76
                    lastMultiple = i;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    77
                }
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    78
                ++i;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    79
            }
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    80
            return ((int)log2base10(lastMultiple) ^ value) != 0 ? lastMultiple + 1 : lastMultiple;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    81
        }
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    82
            }
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    83
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    84
    static final int tableExponent(int cap) {
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    85
        return Log2.log2(cap);
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    86
    }
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    87
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    88
    PerfectHashMap() {
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    89
        this(false, 101);
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    90
    }
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    91
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    92
    PerfectHashMap(int size) {
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    93
        this(false, size);
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    94
    }
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    95
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    96
    PerfectHashMap(boolean minimal, int size) {
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    97
        this.minimal = minimal;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    98
        this.loadMap = new PrimitiveHashMap<>(size);
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
    99
        this.primaryHashFunction = hashFamily.getRandomHashFunction();
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   100
    }
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   101
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   102
    @SuppressWarnings("unchecked")
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   103
    public V getPerfect(long key) {
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   104
        int routeIdx = getIndex(key, primaryHashFunction);
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   105
        assert(routeIdx >= 0);
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   106
        assert(routeIdx < routeTable.length);
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   107
        long element = routeTable[routeIdx];
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   108
        int valueIdx = element < 0 ? getIndex(key, -element - 1) : (int)element;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   109
        assert(valueIdx >= 0);
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   110
        assert(valueIdx < valueTable.length);
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   111
        return (V)valueTable[valueIdx];
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   112
    }
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   113
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   114
    private long getRandomHashFunction() {
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   115
        return hashFamily.getRandomHashFunction();
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   116
    }
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   117
    private int getIndex(long key, long hashFunction) {
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   118
       final int idx = UniversalHashFamily.getIndex(key, hashFunction, shift, shiftMask);
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   119
       assert(idx >= 0);
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   120
       assert(idx < routeTable.length);
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   121
       return idx;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   122
    }
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   123
    private static boolean isColliding(long entry) {
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   124
        return entry < 0;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   125
    }
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   126
    private boolean isNonColliding(long entry) {
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   127
        return entry > 0;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   128
    }
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   129
    private static long setColliding(long entry) {
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   130
        return entry | COLLISION_BIT;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   131
    }
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   132
    private static long read(long entry) {
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   133
        return entry & COLLISION_MASK;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   134
    }
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   135
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   136
    private int nextValueTableSlot(int lastIdx) {
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   137
        assert(lastIdx < valueTable.length);
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   138
        int i = lastIdx;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   139
        for (; i < valueTable.length; ++i) {
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   140
            if (valueTable[i] == null) {
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   141
                break;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   142
            }
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   143
        }
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   144
        return i;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   145
    }
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   146
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   147
    private int valueTableStore(V value, int lastIdx) {
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   148
        if (lastIdx > valueTable.length) {
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   149
            lastIdx = 0;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   150
        }
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   151
        assert(lastIdx < valueTable.length);
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   152
        final int idx = nextValueTableSlot(lastIdx);
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   153
        assert(idx < valueTable.length);
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   154
        assert(valueTable[idx] == null);
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   155
        valueTable[idx] = value;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   156
        return idx;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   157
    }
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   158
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   159
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   160
    private void routeNonCollisions() {
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   161
        int lastIdx = 0;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   162
        for (int i = 0; i < routeTable.length; ++i) {
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   163
            if (isNonColliding(routeTable[i])) {
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   164
                lastIdx = valueTableStore(loadMap.get(routeTable[i]).value, lastIdx);
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   165
                routeTable[i] = lastIdx++;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   166
           }
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   167
        }
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   168
    }
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   169
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   170
    private void rollback(int idx, int length, long hashFunction) {
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   171
        assert(isColliding(routeTable[idx]));
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   172
        long key = read(routeTable[idx]);
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   173
        LinkedValue<V> v = loadMap.get(key); // boxing
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   174
        for (int i = 0; i < length; ++i) {
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   175
            final int valueIdx = getIndex(key, hashFunction);
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   176
            assert(valueIdx >= 0);
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   177
            assert(valueIdx < valueTable.length);
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   178
            assert(valueTable[valueIdx] != null);
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   179
            valueTable[valueIdx] = null;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   180
            key = v.next;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   181
            v = loadMap.get(v.next); // no boxing
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   182
        }
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   183
    }
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   184
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   185
    private boolean remap(int idx, long hashFunction) {
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   186
        assert(isColliding(routeTable[idx]));
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   187
        int completed = 0;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   188
        long key = read(routeTable[idx]);
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   189
        LinkedValue<V> v = loadMap.get(key);
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   190
        while (key != 0) {
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   191
            final int valueIdx = getIndex(key, hashFunction);
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   192
            assert(valueIdx >= 0);
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   193
            assert(valueIdx < valueTable.length);
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   194
            if (valueTable[valueIdx] == null) {
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   195
                valueTable[valueIdx] = v.value;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   196
                ++completed;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   197
                key = v.next;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   198
                v = loadMap.get(v.next);
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   199
                continue;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   200
            }
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   201
            rollback(idx, completed, hashFunction);
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   202
            return false;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   203
        }
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   204
        return true;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   205
    }
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   206
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   207
    private boolean routeCollisions(int idx) {
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   208
        assert(isColliding(routeTable[idx]));
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   209
        boolean success = false;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   210
        int attempts = 0;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   211
        long randomHashFunction = 0;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   212
        do {
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   213
            randomHashFunction = getRandomHashFunction();
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   214
            success = remap(idx, randomHashFunction);
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   215
            if (++attempts == MAX_REMAP_ATTEMPTS) {
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   216
                System.out.println("Failed number of attempts - restart: " + attempts);
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   217
                return false;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   218
            }
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   219
        } while (!success);
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   220
        System.out.println("Number of remap attempts: " + attempts);
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   221
        routeTable[idx] = -1 - randomHashFunction;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   222
        assert(-routeTable[idx] - 1 == randomHashFunction);
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   223
        return true;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   224
    }
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   225
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   226
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   227
    private boolean routeCollisions() {
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   228
        for (int i = 0; i < routeTable.length; ++i) {
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   229
            if (isColliding(routeTable[i])) {
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   230
                if (!routeCollisions(i)) {
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   231
                    return false;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   232
                }
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   233
            }
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   234
        }
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   235
        return true;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   236
    }
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   237
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   238
    private static void clearLongTable(long[] table) {
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   239
        Arrays.fill(table, 0);
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   240
        for (int i = 0; i < table.length; ++i) {
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   241
            assert(table[i] == 0);
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   242
        }
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   243
    }
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   244
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   245
    private static <T extends Object> void clearReferenceTable(T[] table) {
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   246
        Arrays.fill(table, null);
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   247
        for (int i = 0; i < table.length; ++i) {
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   248
            assert(table[i] == null);
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   249
        }
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   250
    }
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   251
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   252
    private void unlinkChains() {
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   253
        for (long key : loadMap.keys()) {
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   254
            loadMap.get(key).next = 0;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   255
        }
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   256
    }
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   257
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   258
    private void routeTableStore(long key, LinkedValue<V> value, int idx) {
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   259
        assert(idx >= 0);
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   260
        assert(idx < routeTable.length);
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   261
        long existing = read(routeTable[idx]);
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   262
        if (existing == 0) {
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   263
            routeTable[idx] = key;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   264
            return;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   265
        }
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   266
        ++collisions;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   267
        routeTable[idx] = setColliding(existing);
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   268
        LinkedValue<V> existingValue = loadMap.get(existing);
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   269
        value.next = existingValue.next;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   270
        existingValue.next = key;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   271
    }
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   272
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   273
    private void mapKeys() {
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   274
        for (long key : loadMap.keys()) {
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   275
            routeTableStore(key, loadMap.get(key), getIndex(key, primaryHashFunction));
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   276
        }
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   277
    }
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   278
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   279
    private void validate() {
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   280
        for (long key : loadMap.keys()) {
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   281
            long element = routeTable[getIndex(key, primaryHashFunction)];
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   282
            int valueIdx = element < 0 ? getIndex(key, -element - 1) : (int)element;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   283
            assert(valueIdx >= 0);
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   284
            assert(loadMap.get(key) == valueTable[valueIdx]);
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   285
        }
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   286
    }
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   287
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   288
    private void reset() {
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   289
        collisions = 0;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   290
        clearLongTable(routeTable);
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   291
        clearReferenceTable(valueTable);
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   292
    }
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   293
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   294
    private int dimensionTableSize() {
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   295
        int size = loadMap.size() * sizeFactor;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   296
        return (int)Log2.log2base10(Log2.log2(size));
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   297
    }
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   298
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   299
    @SuppressWarnings({"rawtypes","unchecked"})
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   300
    private void allocateTables() {
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   301
        int size = dimensionTableSize();
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   302
        this.tableLengthMask = size - 1;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   303
        this.shift = W - tableExponent(size);
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   304
        this.shiftMask = Log2.log2base10(shift) - 1;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   305
        routeTable = new long[size];
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   306
        valueTable = (V[])new Object[size];
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   307
        collisions = 0;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   308
        retries = 0;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   309
    }
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   310
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   311
    public void build() {
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   312
        start:
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   313
        while (true) {
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   314
            allocateTables();
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   315
            System.out.println("Table size " + routeTable.length);
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   316
            mapKeys();
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   317
            if (collisions > 0) {
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   318
                if (!routeCollisions()) {
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   319
                    unlinkChains();
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   320
                    if (++retries <= MAX_ATTEMPS_BEFORE_RESIZE) {
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   321
                      reset();
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   322
                    } else {
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   323
                      sizeFactor *= 2;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   324
                    }
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   325
                    continue start;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   326
                }
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   327
            }
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   328
            routeNonCollisions();
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   329
            return;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   330
        }
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   331
    }
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   332
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   333
    public void rebuild() {
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   334
        sizeFactor = 1;
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   335
        build();
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   336
    }
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   337
    public int size() {
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   338
        return loadMap.size();
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   339
    }
53dccc90a5be Preview-addendum
mgronlun
parents:
diff changeset
   340
}