blob: 9d49596638745be9105216abf8a5974123ebbff8 [file] [log] [blame]
/*
* 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.drill.exec.planner.sql;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentMap;
import com.google.common.collect.Maps;
/**
* A special type of concurrent map which attempts to create an object before returning that it does not exist. It will also provide the same functionality on it's keyset.
* @param <KEY> The key in the map.
* @param <VALUE> The value in the map.
*/
public class ExpandingConcurrentMap<KEY, VALUE> implements ConcurrentMap<KEY, VALUE> {
static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(ExpandingConcurrentMap.class);
private final ConcurrentMap<KEY, VALUE> internalMap = Maps.newConcurrentMap();
private final DelegatingKeySet keySet = new DelegatingKeySet();
private final MapValueFactory<KEY, VALUE> fac;
/**
* Create a new ExpandingConcurrentMap.
* @param fac The object factory responsible for attempting to generate object instances.
*/
public ExpandingConcurrentMap(MapValueFactory<KEY, VALUE> fac) {
super();
this.fac = fac;
}
@Override
public int size() {
return internalMap.size();
}
@Override
public boolean isEmpty() {
return internalMap.isEmpty();
}
public boolean alreadyContainsKey(Object k) {
@SuppressWarnings("unchecked") KEY key = (KEY) k;
if (internalMap.containsKey(key)) {
return true;
}
return false;
}
@Override
public boolean containsKey(Object k) {
@SuppressWarnings("unchecked") KEY key = (KEY) k;
if (internalMap.containsKey(key)) {
return true;
}
VALUE v = getNewEntry(k);
return v != null;
}
@Override
public boolean containsValue(Object value) {
throw new UnsupportedOperationException();
}
@Override
public VALUE get(Object key) {
VALUE out = internalMap.get(key);
if (out != null) {
return out;
}
return getNewEntry(key);
}
private VALUE getNewEntry(Object k) {
@SuppressWarnings("unchecked")
KEY key = (KEY) k;
VALUE v = this.fac.create(key);
if (v == null) {
return null;
}
VALUE old = internalMap.putIfAbsent(key, v);
if (old == null) {
return v;
}
fac.destroy(v);
return old;
}
@Override
public VALUE put(KEY key, VALUE value) {
throw new UnsupportedOperationException();
}
@Override
public VALUE remove(Object key) {
throw new UnsupportedOperationException();
}
@Override
public void putAll(Map<? extends KEY, ? extends VALUE> m) {
throw new UnsupportedOperationException();
}
@Override
public void clear() {
throw new UnsupportedOperationException();
}
@Override
public Set<KEY> keySet() {
return this.keySet;
}
@Override
public Collection<VALUE> values() {
return internalMap.values();
}
@Override
public Set<java.util.Map.Entry<KEY, VALUE>> entrySet() {
return internalMap.entrySet();
}
@Override
public VALUE putIfAbsent(KEY key, VALUE value) {
throw new UnsupportedOperationException();
}
@Override
public boolean remove(Object key, Object value) {
return false;
}
@Override
public boolean replace(KEY key, VALUE oldValue, VALUE newValue) {
return false;
}
@Override
public VALUE replace(KEY key, VALUE value) {
return null;
}
private class DelegatingKeySet implements Set<KEY>{
@Override
public int size() {
return ExpandingConcurrentMap.this.size();
}
@Override
public boolean isEmpty() {
return ExpandingConcurrentMap.this.isEmpty();
}
@Override
public boolean contains(Object o) {
return ExpandingConcurrentMap.this.containsKey(o);
}
@Override
public Iterator<KEY> iterator() {
return internalMap.keySet().iterator();
}
@Override
public Object[] toArray() {
return internalMap.keySet().toArray();
}
@Override
public <T> T[] toArray(T[] a) {
return internalMap.keySet().toArray(a);
}
@Override
public boolean add(KEY e) {
throw new UnsupportedOperationException();
}
@Override
public boolean remove(Object o) {
throw new UnsupportedOperationException();
}
@Override
public boolean containsAll(Collection<?> c) {
for (Object o : c) {
if (this.contains(o)) {
return false;
}
}
return true;
}
@Override
public boolean addAll(Collection<? extends KEY> c) {
throw new UnsupportedOperationException();
}
@Override
public boolean retainAll(Collection<?> c) {
throw new UnsupportedOperationException();
}
@Override
public boolean removeAll(Collection<?> c) {
throw new UnsupportedOperationException();
}
@Override
public void clear() {
throw new UnsupportedOperationException();
}
}
public interface MapValueFactory<KEY, VALUE> {
public VALUE create(KEY key);
public void destroy(VALUE value);
}
}