File: IsolatedHashMap.java

package info (click to toggle)
eclipselink 2.6.9-3
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 44,528 kB
  • sloc: java: 475,126; xml: 72; makefile: 21; sh: 10
file content (191 lines) | stat: -rw-r--r-- 6,752 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
/*******************************************************************************
 * Copyright (c) 2015 Oracle and/or its affiliates, IBM Corporation. All rights reserved.
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
 * which accompanies this distribution.
 * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
 * and the Eclipse Distribution License is available at
 * http://www.eclipse.org/org/documents/edl-v10.php.
 *
 * Contributors:
 *     05/06/2015-2.7 Tomas Kraus
 *       - Initial API and implementation.
 ******************************************************************************/
package org.eclipse.persistence.internal.jpa;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import org.eclipse.persistence.platform.server.ServerPlatform;
import org.eclipse.persistence.platform.server.ServerPlatformUtils;

/**
 * Partition isolated {@link HashMap}. Provides HashMap with partition isolation for {@link ServerPlatform}s
 * that support partitioning. Partition isolation is transparent and keeps {@link Map} API unchanged.
 */
public final class IsolatedHashMap<K, V> implements Map<K, V> {

    /** Default short enough partition ID when server does not support partitions.*/
    private static final String DEFAULT_PARTITION_ID = "0";

    /** Default initial capacity used to create {@link HashMap}s for individual partitions. */
    private static final int DEFAULT_INITIAL_CAPACITY = 16;

    /** Default load factor used to create {@link HashMap}s for individual partitions. */
    private static final float DEFAULT_LOAD_FACTOR = 0.75f;

    /** Detected server platform. */
    private static final ServerPlatform serverPlatform;

    /** Does platform support partitions? */
    private static final boolean supportPartitions;

    /** Class initialization code. */
    static {
        String serverPlatformName = ServerPlatformUtils.detectServerPlatform(null);
        serverPlatform = serverPlatformName != null
                ? ServerPlatformUtils.createServerPlatform(
                        null, serverPlatformName, IsolatedHashMap.class.getClassLoader())
                : null;
        // False value also handles cases when serverPlatform is null to avoid NPE.
        supportPartitions = serverPlatform != null ? serverPlatform.usesPartitions() : false;
    }

    /**
     * INTERNAL:
     * Partition isolated {@link Map} factory. Provides {@link Map} separated for individual partitions.
     * Factory method will return {@link HashMap} on platforms without partitions support. Slower
     * {@link IsolatedHashMap} instance will be used only on platforms with partitions support.
     */
    public static final <K, V>Map<K, V> newMap() {
        return supportPartitions ? new IsolatedHashMap<K, V>() : new HashMap<K, V>();
    }

    /** Initial capacity used to create {@link HashMap}s for individual partitions. */
    private final int initialCapacity;

    /** Initial load factor used to create {@link HashMap}s for individual partitions. */
    private final float loadFactor;

    /** Partition ID to {@link Map} mapping. Used when platform does support partitions. */
    private final Map<String, Map<K, V>> maps;

    /**
     * Constructs an empty {@code IsolatedHashMap} with the default initial capacity {@code 16} and the default
     * load factor {@code 0.75} for every partition.
     */
    private IsolatedHashMap() {
        this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR);
    }

    /**
     * Constructs an empty {@code IsolatedHashMap} with the initial capacity and the default
     * load factor specified as arguments.
     * @param initialCapacity Initial capacity used to create {@link HashMap}s for individual partitions.
     * @param loadFactor      Initial load factor used used to create {@link HashMap}s for individual partitions.
     */
    private IsolatedHashMap(final int initialCapacity, final float loadFactor) {
        this.initialCapacity = initialCapacity;
        this.loadFactor = loadFactor;
        maps = new ConcurrentHashMap<>(8);
    }

    /**
     * Get {@link Map} for current partition.
     * @return {@link Map} for current partition. Will never return {@code null}.
     */
    private Map<K, V> getMap() {
        String partitionId = supportPartitions ? serverPlatform.getPartitionID() : DEFAULT_PARTITION_ID;
        Map<K, V> partitionMap = maps.get(partitionId);
        // First null check to skip locking when map is already initialized.
        if (partitionMap == null) {
            // FindBugs would be complaining about locking on maps so this is used to shut it up.
            synchronized(this) {
                // Second null check while having lock.
                partitionMap = maps.get(partitionId);
                if (partitionMap == null) {
                    partitionMap = new HashMap<>(initialCapacity, loadFactor);
                    maps.put(partitionId, partitionMap);
                }
            }
        }
        return partitionMap;
    }

    // All Map interface methods are delegated to Map mapped to current partition.
    /** {@inheritDoc} */
    @Override
    public int size() {
        return getMap().size();
    }

    /** {@inheritDoc} */
    @Override
    public boolean isEmpty() {
        return getMap().isEmpty();
    }

    /** {@inheritDoc} */
    @Override
    public boolean containsKey(Object key) {
        return getMap().containsKey(key);
    }

    /** {@inheritDoc} */
    @Override
    public boolean containsValue(Object value) {
        return getMap().containsValue(value);
    }

    /** {@inheritDoc} */
    @Override
    public V get(Object key) {
        return getMap().get(key);
    }

    /** {@inheritDoc} */
    @Override
    public V put(K key, V value) {
        return getMap().put(key, value);
    }

    /** {@inheritDoc} */
    @Override
    public V remove(Object key) {
        return getMap().remove(key);
    }

    /** {@inheritDoc} */
    @Override
    public void putAll(Map<? extends K, ? extends V> m) {
        getMap().putAll(m);
    }

    /** {@inheritDoc} */
    @Override
    public void clear() {
        getMap().clear();
    }

    /** {@inheritDoc} */
    @Override
    public Set<K> keySet() {
        return getMap().keySet();
    }

    /** {@inheritDoc} */
    @Override
    public Collection<V> values() {
        return getMap().values();
    }

    /** {@inheritDoc} */
    @Override
    public Set<java.util.Map.Entry<K, V>> entrySet() {
        return getMap().entrySet();
    }

}