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

org.apache.hadoop.hbase.util.PoolMap Maven / Gradle / Ivy

There is a newer version: 3.0.0-beta-1
Show newest version
/**
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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 org.apache.hadoop.hbase.util;

import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.classification.InterfaceStability;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicInteger;

/**
 *
 * The PoolMap maps a key to a collection of values, the elements
 * of which are managed by a pool. In effect, that collection acts as a shared
 * pool of resources, access to which is closely controlled as per the semantics
 * of the pool.
 *
 * 

* In case the size of the pool is set to a non-zero positive number, that is * used to cap the number of resources that a pool may contain for any given * key. A size of {@link Integer#MAX_VALUE} is interpreted as an unbounded pool. *

* * @param * the type of the key to the resource * @param * the type of the resource being pooled */ @InterfaceAudience.Public @InterfaceStability.Evolving public class PoolMap implements Map { private PoolType poolType; private int poolMaxSize; private Map> pools = new ConcurrentHashMap>(); public PoolMap(PoolType poolType) { this.poolType = poolType; } public PoolMap(PoolType poolType, int poolMaxSize) { this.poolType = poolType; this.poolMaxSize = poolMaxSize; } @Override public V get(Object key) { Pool pool = pools.get(key); return pool != null ? pool.get() : null; } @Override public V put(K key, V value) { Pool pool = pools.get(key); if (pool == null) { pools.put(key, pool = createPool()); } return pool != null ? pool.put(value) : null; } @SuppressWarnings("unchecked") @Override public V remove(Object key) { Pool pool = pools.remove(key); if (pool != null) { remove((K) key, pool.get()); } return null; } public boolean remove(K key, V value) { Pool pool = pools.get(key); boolean res = false; if (pool != null) { res = pool.remove(value); if (res && pool.size() == 0) { pools.remove(key); } } return res; } @Override public Collection values() { Collection values = new ArrayList(); for (Pool pool : pools.values()) { Collection poolValues = pool.values(); if (poolValues != null) { values.addAll(poolValues); } } return values; } public Collection values(K key) { Collection values = new ArrayList(); Pool pool = pools.get(key); if (pool != null) { Collection poolValues = pool.values(); if (poolValues != null) { values.addAll(poolValues); } } return values; } @Override public boolean isEmpty() { return pools.isEmpty(); } @Override public int size() { return pools.size(); } public int size(K key) { Pool pool = pools.get(key); return pool != null ? pool.size() : 0; } @Override public boolean containsKey(Object key) { return pools.containsKey(key); } @Override public boolean containsValue(Object value) { if (value == null) { return false; } for (Pool pool : pools.values()) { if (value.equals(pool.get())) { return true; } } return false; } @Override public void putAll(Map map) { for (Map.Entry entry : map.entrySet()) { put(entry.getKey(), entry.getValue()); } } @Override public void clear() { for (Pool pool : pools.values()) { pool.clear(); } pools.clear(); } @Override public Set keySet() { return pools.keySet(); } @Override public Set> entrySet() { Set> entries = new HashSet>(); for (Map.Entry> poolEntry : pools.entrySet()) { final K poolKey = poolEntry.getKey(); final Pool pool = poolEntry.getValue(); if (pool != null) { for (final V poolValue : pool.values()) { entries.add(new Map.Entry() { @Override public K getKey() { return poolKey; } @Override public V getValue() { return poolValue; } @Override public V setValue(V value) { return pool.put(value); } }); } } } return null; } protected interface Pool { public R get(); public R put(R resource); public boolean remove(R resource); public void clear(); public Collection values(); public int size(); } public enum PoolType { Reusable, ThreadLocal, RoundRobin; public static PoolType valueOf(String poolTypeName, PoolType defaultPoolType, PoolType... allowedPoolTypes) { PoolType poolType = PoolType.fuzzyMatch(poolTypeName); if (poolType != null) { boolean allowedType = false; if (poolType.equals(defaultPoolType)) { allowedType = true; } else { if (allowedPoolTypes != null) { for (PoolType allowedPoolType : allowedPoolTypes) { if (poolType.equals(allowedPoolType)) { allowedType = true; break; } } } } if (!allowedType) { poolType = null; } } return (poolType != null) ? poolType : defaultPoolType; } public static String fuzzyNormalize(String name) { return name != null ? name.replaceAll("-", "").trim().toLowerCase() : ""; } public static PoolType fuzzyMatch(String name) { for (PoolType poolType : values()) { if (fuzzyNormalize(name).equals(fuzzyNormalize(poolType.name()))) { return poolType; } } return null; } } protected Pool createPool() { switch (poolType) { case Reusable: return new ReusablePool(poolMaxSize); case RoundRobin: return new RoundRobinPool(poolMaxSize); case ThreadLocal: return new ThreadLocalPool(); } return null; } /** * The ReusablePool represents a {@link PoolMap.Pool} that builds * on the {@link LinkedList} class. It essentially allows resources to be * checked out, at which point it is removed from this pool. When the resource * is no longer required, it should be returned to the pool in order to be * reused. * *

* If {@link #maxSize} is set to {@link Integer#MAX_VALUE}, then the size of * the pool is unbounded. Otherwise, it caps the number of consumers that can * check out a resource from this pool to the (non-zero positive) value * specified in {@link #maxSize}. *

* * @param * the type of the resource */ @SuppressWarnings("serial") public class ReusablePool extends ConcurrentLinkedQueue implements Pool { private int maxSize; public ReusablePool(int maxSize) { this.maxSize = maxSize; } @Override public R get() { return poll(); } @Override public R put(R resource) { if (super.size() < maxSize) { add(resource); } return null; } @Override public Collection values() { return this; } } /** * The RoundRobinPool represents a {@link PoolMap.Pool}, which * stores its resources in an {@link ArrayList}. It load-balances access to * its resources by returning a different resource every time a given key is * looked up. * *

* If {@link #maxSize} is set to {@link Integer#MAX_VALUE}, then the size of * the pool is unbounded. Otherwise, it caps the number of resources in this * pool to the (non-zero positive) value specified in {@link #maxSize}. *

* * @param * the type of the resource * */ @SuppressWarnings("serial") class RoundRobinPool extends CopyOnWriteArrayList implements Pool { private int maxSize; private int nextResource = 0; public RoundRobinPool(int maxSize) { this.maxSize = maxSize; } @Override public R put(R resource) { if (super.size() < maxSize) { add(resource); } return null; } @Override public R get() { if (super.size() < maxSize) { return null; } nextResource %= super.size(); R resource = get(nextResource++); return resource; } @Override public Collection values() { return this; } } /** * The ThreadLocalPool represents a {@link PoolMap.Pool} that * builds on the {@link ThreadLocal} class. It essentially binds the resource * to the thread from which it is accessed. * *

* Note that the size of the pool is essentially bounded by the number of threads * that add resources to this pool. *

* * @param * the type of the resource */ static class ThreadLocalPool extends ThreadLocal implements Pool { private static final Map, AtomicInteger> poolSizes = new HashMap, AtomicInteger>(); public ThreadLocalPool() { } @Override public R put(R resource) { R previousResource = get(); if (previousResource == null) { AtomicInteger poolSize = poolSizes.get(this); if (poolSize == null) { poolSizes.put(this, poolSize = new AtomicInteger(0)); } poolSize.incrementAndGet(); } this.set(resource); return previousResource; } @Override public void remove() { super.remove(); AtomicInteger poolSize = poolSizes.get(this); if (poolSize != null) { poolSize.decrementAndGet(); } } @Override public int size() { AtomicInteger poolSize = poolSizes.get(this); return poolSize != null ? poolSize.get() : 0; } @Override public boolean remove(R resource) { R previousResource = super.get(); if (resource != null && resource.equals(previousResource)) { remove(); return true; } else { return false; } } @Override public void clear() { super.remove(); } @Override public Collection values() { List values = new ArrayList(); values.add(get()); return values; } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy