Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/**
* 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.types;
import java.util.AbstractMap;
import java.util.Collection;
import java.util.Comparator;
import java.util.Iterator;
import java.util.Map;
import java.util.NavigableSet;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.SortedSet;
import java.util.concurrent.ConcurrentNavigableMap;
import org.apache.yetus.audience.InterfaceAudience;
import org.apache.yetus.audience.InterfaceStability;
/**
* A Map that keeps a sorted array in order to provide the concurrent map interface.
* Keeping a sorted array means that it's much more cache line friendly, making reads faster
* than the tree version.
*
* In order to make concurrent reads and writes safe this does a copy on write.
* There can only be one concurrent write at a time.
*/
@InterfaceAudience.Private
@InterfaceStability.Stable
public class CopyOnWriteArrayMap extends AbstractMap
implements Map, ConcurrentNavigableMap {
private final Comparator keyComparator;
private volatile ArrayHolder holder;
public CopyOnWriteArrayMap() {
this(new Comparator() {
@Override
public int compare(K o1, K o2) {
return ((Comparable) o1).compareTo(o2);
}
});
}
public CopyOnWriteArrayMap(final Comparator keyComparator) {
this.keyComparator = keyComparator;
this.holder = new ArrayHolder<>(keyComparator, new Comparator>() {
@Override
public int compare(Entry o1, Entry o2) {
return keyComparator.compare(o1.getKey(), o2.getKey());
}
});
}
private CopyOnWriteArrayMap(final Comparator keyComparator, ArrayHolder holder) {
this.keyComparator = keyComparator;
this.holder = holder;
}
/*
Un synchronized read operations.
No locking.
No waiting
No copying.
These should all be FAST.
*/
@Override
public Comparator comparator() {
return keyComparator;
}
@Override
public ConcurrentNavigableMap tailMap(K fromKey, boolean inclusive) {
ArrayHolder current = this.holder;
int index = current.find(fromKey);
if (!inclusive && index >= 0) {
index++;
} else if (index < 0) {
index = -(index + 1);
}
return new CopyOnWriteArrayMap<>(
this.keyComparator,
new ArrayHolder<>(
current.entries,
index,
current.endIndex,
current.keyComparator,
current.comparator));
}
@Override
public ConcurrentNavigableMap tailMap(K fromKey) {
return this.tailMap(fromKey, true);
}
@Override
public K firstKey() {
ArrayHolder current = this.holder;
if (current.getLength() == 0) {
return null;
}
return current.entries[current.startIndex].getKey();
}
@Override
public K lastKey() {
ArrayHolder current = this.holder;
if (current.getLength() == 0) {
return null;
}
return current.entries[current.endIndex - 1].getKey();
}
@Override
public Entry lowerEntry(K key) {
ArrayHolder current = this.holder;
if (current.getLength() == 0) {
return null;
}
int index = current.find(key);
// There's a key exactly equal.
if (index >= 0) {
index -= 1;
} else {
index = -(index + 1) - 1;
}
if (index < current.startIndex || index >= current.endIndex) {
return null;
}
return current.entries[index];
}
@Override
public K lowerKey(K key) {
Map.Entry entry = lowerEntry(key);
if (entry == null) {
return null;
}
return entry.getKey();
}
@Override
public Entry floorEntry(K key) {
ArrayHolder current = this.holder;
if (current.getLength() == 0) {
return null;
}
int index = current.find(key);
if (index < 0) {
index = -(index + 1) - 1;
}
if (index < current.startIndex || index >= current.endIndex) {
return null;
}
return current.entries[index];
}
@Override
public K floorKey(K key) {
Map.Entry entry = floorEntry(key);
if (entry == null) {
return null;
}
return entry.getKey();
}
@Override
public Entry ceilingEntry(K key) {
ArrayHolder current = this.holder;
if (current.getLength() == 0) {
return null;
}
int index = current.find(key);
if (index < 0) {
index = -(index + 1);
}
if (index < current.startIndex || index >= current.endIndex) {
return null;
}
return current.entries[index];
}
@Override
public K ceilingKey(K key) {
Map.Entry entry = ceilingEntry(key);
if (entry == null) {
return null;
}
return entry.getKey();
}
@Override
public Entry higherEntry(K key) {
ArrayHolder current = this.holder;
if (current.getLength() == 0) {
return null;
}
int index = current.find(key);
// There's a key exactly equal.
if (index >= 0) {
index += 1;
} else {
index = -(index + 1);
}
if (index < current.startIndex || index >= current.endIndex) {
return null;
}
return current.entries[index];
}
@Override
public K higherKey(K key) {
Map.Entry entry = higherEntry(key);
if (entry == null) {
return null;
}
return entry.getKey();
}
@Override
public Entry firstEntry() {
ArrayHolder current = this.holder;
if (current.getLength() == 0) {
return null;
}
return current.entries[current.startIndex];
}
@Override
public Entry lastEntry() {
ArrayHolder current = this.holder;
if (current.getLength() == 0) {
return null;
}
return current.entries[current.endIndex - 1];
}
@Override
public int size() {
return holder.getLength();
}
@Override
public boolean isEmpty() {
return holder.getLength() == 0;
}
@Override
public boolean containsKey(Object key) {
ArrayHolder current = this.holder;
int index = current.find((K) key);
return index >= 0;
}
@Override
public V get(Object key) {
ArrayHolder current = this.holder;
int index = current.find((K) key);
if (index >= 0) {
return current.entries[index].getValue();
}
return null;
}
@Override
public NavigableSet keySet() {
return new ArrayKeySet<>(this.holder);
}
@Override
public Collection values() {
return new ArrayValueCollection<>(this.holder);
}
@Override
public Set> entrySet() {
return new ArrayEntrySet<>(this.holder);
}
/*
Synchronized write methods.
Every method should be synchronized.
Only one modification at a time.
These will be slow.
*/
@Override
public synchronized V put(K key, V value) {
ArrayHolder current = this.holder;
int index = current.find(key);
COWEntry newEntry = new COWEntry<>(key, value);
if (index >= 0) {
this.holder = current.replace(index, newEntry);
return current.entries[index].getValue();
} else {
this.holder = current.insert(-(index + 1), newEntry);
}
return null;
}
@Override
public synchronized V remove(Object key) {
ArrayHolder current = this.holder;
int index = current.find((K) key);
if (index >= 0) {
this.holder = current.remove(index);
return current.entries[index].getValue();
}
return null;
}
@Override
public synchronized void clear() {
this.holder = new ArrayHolder<>(this.holder.keyComparator, this.holder.comparator);
}
@Override
public synchronized V putIfAbsent(K key, V value) {
ArrayHolder current = this.holder;
int index = current.find(key);
if (index < 0) {
COWEntry newEntry = new COWEntry<>(key, value);
this.holder = current.insert(-(index + 1), newEntry);
return value;
}
return current.entries[index].getValue();
}
@Override
public synchronized boolean remove(Object key, Object value) {
ArrayHolder current = this.holder;
int index = current.find((K) key);
if (index >= 0 && current.entries[index].getValue().equals(value)) {
this.holder = current.remove(index);
return true;
}
return false;
}
@Override
public synchronized boolean replace(K key, V oldValue, V newValue) {
ArrayHolder current = this.holder;
int index = current.find(key);
if (index >= 0 && current.entries[index].getValue().equals(oldValue)) {
COWEntry newEntry = new COWEntry<>(key, newValue);
this.holder = current.replace(index, newEntry);
return true;
}
return false;
}
@Override
public synchronized V replace(K key, V value) {
ArrayHolder current = this.holder;
int index = current.find(key);
if (index >= 0) {
COWEntry newEntry = new COWEntry<>(key, value);
this.holder = current.replace(index, newEntry);
return current.entries[index].getValue();
}
return null;
}
@Override
public Entry pollFirstEntry() {
throw new UnsupportedOperationException();
}
@Override
public Entry pollLastEntry() {
throw new UnsupportedOperationException();
}
@Override
public ConcurrentNavigableMap descendingMap() {
throw new UnsupportedOperationException();
}
@Override
public NavigableSet navigableKeySet() {
throw new UnsupportedOperationException();
}
@Override
public ConcurrentNavigableMap subMap(K fromKey, K toKey) {
throw new UnsupportedOperationException();
}
@Override
public ConcurrentNavigableMap headMap(K toKey) {
throw new UnsupportedOperationException();
}
@Override
public ConcurrentNavigableMap subMap(K fromKey,
boolean fromInclusive,
K toKey,
boolean toInclusive) {
throw new UnsupportedOperationException();
}
@Override
public ConcurrentNavigableMap headMap(K toKey, boolean inclusive) {
throw new UnsupportedOperationException();
}
@Override
public NavigableSet descendingKeySet() {
throw new UnsupportedOperationException();
}
private final class ArrayKeySet implements NavigableSet {
private final ArrayHolder holder;
private ArrayKeySet(ArrayHolder holder) {
this.holder = holder;
}
@Override
public int size() {
return holder.getLength();
}
@Override
public boolean isEmpty() {
return holder.getLength() == 0;
}
@Override
public boolean contains(Object o) {
ArrayHolder current = this.holder;
for (int i = current.startIndex; i < current.endIndex; i++) {
if (current.entries[i].getValue().equals(o)) {
return true;
}
}
return false;
}
@Override
public K lower(K k) {
throw new UnsupportedOperationException();
}
@Override
public K floor(K k) {
throw new UnsupportedOperationException();
}
@Override
public K ceiling(K k) {
throw new UnsupportedOperationException();
}
@Override
public K higher(K k) {
throw new UnsupportedOperationException();
}
@Override
public K pollFirst() {
throw new UnsupportedOperationException();
}
@Override
public K pollLast() {
throw new UnsupportedOperationException();
}
@Override
public Iterator iterator() {
return new ArrayKeyIterator<>(this.holder);
}
@Override
public NavigableSet descendingSet() {
throw new UnsupportedOperationException();
}
@Override
public Iterator descendingIterator() {
throw new UnsupportedOperationException();
}
@Override
public NavigableSet subSet(K fromElement,
boolean fromInclusive,
K toElement,
boolean toInclusive) {
throw new UnsupportedOperationException();
}
@Override
public NavigableSet headSet(K toElement, boolean inclusive) {
throw new UnsupportedOperationException();
}
@Override
public NavigableSet tailSet(K fromElement, boolean inclusive) {
throw new UnsupportedOperationException();
}
@Override
public Comparator comparator() {
return (Comparator) keyComparator;
}
@Override
public SortedSet subSet(K fromElement, K toElement) {
return null;
}
@Override
public SortedSet headSet(K toElement) {
return null;
}
@Override
public SortedSet tailSet(K fromElement) {
return null;
}
@Override
public K first() {
ArrayHolder current = this.holder;
if (current.getLength() == 0) {
return null;
}
return current.entries[current.startIndex].getKey();
}
@Override
public K last() {
ArrayHolder current = this.holder;
if (current.getLength() == 0) {
return null;
}
return current.entries[current.endIndex - 1].getKey();
}
@Override
public Object[] toArray() {
throw new UnsupportedOperationException();
}
@Override
public T[] toArray(T[] a) {
throw new UnsupportedOperationException();
}
@Override
public boolean add(K k) {
throw new UnsupportedOperationException();
}
@Override
public boolean remove(Object o) {
throw new UnsupportedOperationException();
}
@Override
public boolean containsAll(Collection c) {
throw new UnsupportedOperationException();
}
@Override
public boolean addAll(Collection 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();
}
}
private final class ArrayValueCollection implements Collection {
private final ArrayHolder holder;
private ArrayValueCollection(ArrayHolder holder) {
this.holder = holder;
}
@Override
public int size() {
return holder.getLength();
}
@Override
public boolean isEmpty() {
return holder.getLength() == 0;
}
@Override
public boolean contains(Object o) {
throw new UnsupportedOperationException();
}
@Override
public Iterator iterator() {
return new ArrayValueIterator<>(this.holder);
}
@Override
public Object[] toArray() {
throw new UnsupportedOperationException();
}
@Override
public T[] toArray(T[] a) {
throw new UnsupportedOperationException();
}
@Override
public boolean add(V v) {
throw new UnsupportedOperationException();
}
@Override
public boolean remove(Object o) {
throw new UnsupportedOperationException();
}
@Override
public boolean containsAll(Collection c) {
throw new UnsupportedOperationException();
}
@Override
public boolean addAll(Collection c) {
throw new UnsupportedOperationException();
}
@Override
public boolean removeAll(Collection c) {
throw new UnsupportedOperationException();
}
@Override
public boolean retainAll(Collection c) {
throw new UnsupportedOperationException();
}
@Override
public void clear() {
throw new UnsupportedOperationException();
}
@Override
@edu.umd.cs.findbugs.annotations.SuppressWarnings(value="EQ_ALWAYS_FALSE",
justification="Intentional")
public boolean equals(Object o) {
return false; // FindBugs: Causes EQ_ALWAYS_FALSE. Suppressed.
}
@Override
public int hashCode() {
return 0;
}
}
private static final class ArrayKeyIterator implements Iterator {
int index;
private final ArrayHolder holder;
private ArrayKeyIterator(ArrayHolder holder) {
this.holder = holder;
index = holder.startIndex;
}
@Override
public boolean hasNext() {
return index < holder.endIndex;
}
@Override
public K next() {
return holder.entries[index++].getKey();
}
@Override
public void remove() {
throw new UnsupportedOperationException("remove");
}
}
private static final class ArrayValueIterator implements Iterator {
int index;
private final ArrayHolder holder;
private ArrayValueIterator(ArrayHolder holder) {
this.holder = holder;
index = holder.startIndex;
}
@Override
public boolean hasNext() {
return index < holder.endIndex;
}
@Override
public V next() {
return holder.entries[index++].getValue();
}
@Override
public void remove() {
throw new UnsupportedOperationException("remove");
}
}
private static final class ArrayEntryIterator implements Iterator> {
int index;
private final ArrayHolder holder;
private ArrayEntryIterator(ArrayHolder holder) {
this.holder = holder;
this.index = holder.startIndex;
}
@Override
public boolean hasNext() {
return index < holder.endIndex;
}
@Override
@edu.umd.cs.findbugs.annotations.SuppressWarnings(value="IT_NO_SUCH_ELEMENT",
justification="Intentional")
public Entry next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
return holder.entries[index++];
}
@Override
public void remove() {
throw new UnsupportedOperationException("remove");
}
}
private final class ArrayEntrySet implements Set> {
private final ArrayHolder holder;
private ArrayEntrySet(ArrayHolder holder) {
this.holder = holder;
}
@Override
public int size() {
return holder.getLength();
}
@Override
public boolean isEmpty() {
return holder.getLength() == 0;
}
@Override
public boolean contains(Object o) {
return false;
}
@Override
public Iterator> iterator() {
return new ArrayEntryIterator<>(this.holder);
}
@Override
public Object[] toArray() {
throw new UnsupportedOperationException();
}
@Override
public T[] toArray(T[] a) {
throw new UnsupportedOperationException();
}
@Override
public boolean add(Entry kvEntry) {
throw new UnsupportedOperationException();
}
@Override
public boolean remove(Object o) {
throw new UnsupportedOperationException();
}
@Override
public boolean containsAll(Collection c) {
throw new UnsupportedOperationException();
}
@Override
public boolean addAll(Collection> 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();
}
}
private final static class ArrayHolder {
private final COWEntry[] entries;
private final int startIndex;
private final int endIndex;
private final Comparator keyComparator;
private final Comparator> comparator;
int getLength() {
return endIndex - startIndex;
}
/**
* Binary search for a given key
* @param needle The key to look for in all of the entries
* @return Same return value as Arrays.binarySearch.
* Positive numbers mean the index. Otherwise (-1 * insertion point) - 1
*/
int find(K needle) {
int begin = startIndex;
int end = endIndex - 1;
while (begin <= end) {
int mid = begin + ((end - begin) / 2);
K midKey = entries[ mid].key;
int compareRes = keyComparator.compare(midKey, needle);
// 0 means equals
// We found the key.
if (compareRes == 0) {
return mid;
} else if (compareRes < 0) {
// midKey is less than needle so we need
// to look at farther up
begin = mid + 1;
} else {
// midKey is greater than needle so we
// need to look down.
end = mid - 1;
}
}
return (-1 * begin) - 1;
}
ArrayHolder replace(int index, COWEntry newEntry) {
// TODO should this restart the array back at start index 0 ?
COWEntry[] newEntries = entries.clone();
newEntries[index] = newEntry;
return new ArrayHolder<>(newEntries, startIndex, endIndex, keyComparator, comparator);
}
ArrayHolder remove(int index) {
COWEntry[] newEntries = new COWEntry[getLength() - 1];
System.arraycopy(this.entries, startIndex, newEntries, 0, index - startIndex);
System.arraycopy(this.entries, index + 1, newEntries, index, entries.length - index - 1);
return new ArrayHolder<>(newEntries, 0, newEntries.length, keyComparator, comparator);
}
ArrayHolder insert(int index, COWEntry newEntry) {
COWEntry[] newEntries = new COWEntry[getLength() + 1];
System.arraycopy(this.entries, startIndex, newEntries, 0, index - startIndex);
newEntries[index] = newEntry;
System.arraycopy(this.entries, index, newEntries, index + 1, getLength() - index);
return new ArrayHolder<>(newEntries, 0, newEntries.length, keyComparator, comparator);
}
private ArrayHolder(
final Comparator keyComparator,
final Comparator> comparator) {
this.endIndex = 0;
this.startIndex = 0;
this.entries = new COWEntry[] {};
this.keyComparator = keyComparator;
this.comparator = comparator;
}
private ArrayHolder(COWEntry[] entries,
int startIndex, int endIndex,
final Comparator keyComparator,
Comparator> comparator) {
this.entries = entries;
this.startIndex = startIndex;
this.endIndex = endIndex;
this.keyComparator = keyComparator;
this.comparator = comparator;
}
}
private final static class COWEntry implements Map.Entry {
K key = null;
V value = null;
COWEntry(K key, V value) {
this.key = key;
this.value = value;
}
@Override
public K getKey() {
return key;
}
@Override
public V getValue() {
return value;
}
@Override
public V setValue(V value) {
V oldValue = this.value;
this.value = value;
return oldValue;
}
}
}