org.apache.cassandra.repair.asymmetric.RangeMap Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of cassandra-all Show documentation
Show all versions of cassandra-all Show documentation
The Apache Cassandra Project develops a highly scalable second-generation distributed database, bringing together Dynamo's fully distributed design and Bigtable's ColumnFamily-based data model.
/*
* 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.cassandra.repair.asymmetric;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NavigableMap;
import java.util.Objects;
import java.util.Set;
import java.util.TreeMap;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.AbstractIterator;
import org.apache.cassandra.dht.Range;
import org.apache.cassandra.dht.Token;
public class RangeMap implements Map, T>
{
private static final Comparator> comparator = Comparator.comparing((Range o) -> o.left);
private final NavigableMap, T> byStart;
public RangeMap()
{
byStart = new TreeMap<>(comparator);
}
public int size()
{
return byStart.size();
}
public boolean isEmpty()
{
return byStart.isEmpty();
}
public boolean containsKey(Object key)
{
return byStart.containsKey(key);
}
public boolean containsValue(Object value)
{
return byStart.containsValue(value);
}
public T get(Object key)
{
return byStart.get(key);
}
public T put(Range key, T value)
{
assertNonIntersecting(key);
return byStart.put(key, value);
}
private void assertNonIntersecting(Range range)
{
// todo: wraparound
Range before = byStart.floorKey(range);
Range after = byStart.ceilingKey(range);
assert before == null || !before.intersects(range);
assert after == null || !after.intersects(range);
}
public T remove(Object key)
{
return byStart.remove(key);
}
public void putAll(Map extends Range, ? extends T> m)
{
byStart.putAll(m);
}
public void clear()
{
byStart.clear();
}
public Set> keySet()
{
return byStart.keySet();
}
public Collection values()
{
return byStart.values();
}
public Set, T>> entrySet()
{
return byStart.entrySet();
}
/**
* might return duplicate entries if range.isWrapAround()
*
* don't depend on the order of the entries returned
*/
@VisibleForTesting
Iterator, T>> intersectingEntryIterator(Range range)
{
return range.isWrapAround() ? new WrappingIntersectingIterator(range) : new IntersectingIterator(range);
}
public Set, T>> removeIntersecting(Range range)
{
Iterator, T>> iter = intersectingEntryIterator(range);
Set, T>> intersecting = new HashSet<>();
while (iter.hasNext())
{
Map.Entry, T> entry = iter.next();
intersecting.add(entry);
}
for (Map.Entry, T> entry : intersecting)
byStart.remove(entry.getKey());
return intersecting;
}
private class WrappingIntersectingIterator extends AbstractIterator, T>>
{
private final Iterator, T>>> iterators;
private Iterator, T>> currentIter;
public WrappingIntersectingIterator(Range range)
{
List, T>>> iters = new ArrayList<>(2);
for (Range unwrapped : range.unwrap())
iters.add((new IntersectingIterator(unwrapped)));
iterators = iters.iterator();
}
protected Map.Entry, T> computeNext()
{
while (currentIter == null || !currentIter.hasNext())
{
if (!iterators.hasNext())
return endOfData();
currentIter = iterators.next();
}
return currentIter.next();
}
}
private class IntersectingIterator extends AbstractIterator, T>>
{
private final Iterator, T>> tailIterator;
private final Range range;
// since we guarantee no ranges overlap in byStart, we know the last entry is possibly the wrap around range
private boolean shouldReturnLast = false;
public IntersectingIterator(Range range)
{
Range startKey = byStart.floorKey(range);
tailIterator = startKey == null ? byStart.entrySet().iterator() :
byStart.tailMap(startKey, true).entrySet().iterator();
Range last = byStart.isEmpty() ? null : byStart.lastKey();
if (last != null && last.isWrapAround() && last.intersects(range))
shouldReturnLast = true;
this.range = range;
}
protected Map.Entry, T> computeNext()
{
if (shouldReturnLast)
{
shouldReturnLast = false;
return new Entry<>(byStart.lastEntry());
}
while (tailIterator.hasNext())
{
Entry, T> candidateNext = new Entry<>(tailIterator.next());
Range candidateRange = candidateNext.getKey();
if (candidateRange.isWrapAround()) // we know we already returned any wrapping range
continue;
if (candidateRange.left.compareTo(range.right) >= 0 && (!range.isWrapAround())) // range is unwrapped, but that means one range has right == min token and is still wrapping
return endOfData();
if (range.left.compareTo(candidateRange.right) >= 0)
continue;
return candidateNext;
}
return endOfData();
}
}
public String toString()
{
return byStart.toString();
}
static class Entry implements Map.Entry
{
private final V v;
private final K k;
Entry(K key, V val)
{
this.k = key;
this.v = val;
}
Entry(Map.Entry toClone)
{
this(toClone.getKey(), toClone.getValue());
}
public K getKey()
{
return k;
}
public V getValue()
{
return v;
}
public V setValue(V value)
{
throw new UnsupportedOperationException();
}
public boolean equals(Object o)
{
if (this == o) return true;
if (!(o instanceof Map.Entry)) return false;
Map.Entry, ?> entry = (Map.Entry, ?>) o;
return v.equals(entry.getValue()) &&
k.equals(entry.getKey());
}
public int hashCode()
{
return Objects.hash(v, k);
}
public String toString()
{
return "Entry{" +
"v=" + v +
", k=" + k +
'}';
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy