All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.persistence.internal.jpa.IsolatedHashMap Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2015, 2024 Oracle and/or its affiliates. All rights reserved.
 * Copyright (c) 2015, 2024 IBM Corporation. All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v. 2.0 which is available at
 * http://www.eclipse.org/legal/epl-2.0,
 * or the Eclipse Distribution License v. 1.0 which is available at
 * http://www.eclipse.org/org/documents/edl-v10.php.
 *
 * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
 */

// 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 implements Map {

    /** 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 Map newMap() {
        return supportPartitions ? new IsolatedHashMap<>() : new HashMap<>();
    }

    /** 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> 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 getMap() {
        String partitionId = supportPartitions ? serverPlatform.getPartitionID() : DEFAULT_PARTITION_ID;
        Map 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.

    @Override
    public int size() {
        return getMap().size();
    }


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


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


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


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


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


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


    @Override
    public void putAll(Map m) {
        getMap().putAll(m);
    }


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


    @Override
    public Set keySet() {
        return getMap().keySet();
    }


    @Override
    public Collection values() {
        return getMap().values();
    }


    @Override
    public Set> entrySet() {
        return getMap().entrySet();
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy