org.apache.cassandra.locator.PendingRangeMaps 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.locator;
import java.util.Comparator;
import java.util.Iterator;
import java.util.Map;
import java.util.NavigableMap;
import java.util.TreeMap;
import com.google.common.collect.Iterators;
import org.apache.cassandra.dht.Range;
import org.apache.cassandra.dht.Token;
import org.apache.cassandra.locator.ReplicaCollection.Builder.Conflict;
import org.apache.cassandra.utils.FBUtilities;
import static org.apache.cassandra.config.CassandraRelevantProperties.LINE_SEPARATOR;
public class PendingRangeMaps implements Iterable, EndpointsForRange.Builder>>
{
/**
* We have for NavigableMap to be able to search for ranges containing a token efficiently.
*
* First two are for non-wrap-around ranges, and the last two are for wrap-around ranges.
*/
// ascendingMap will sort the ranges by the ascending order of right token
private final NavigableMap, EndpointsForRange.Builder> ascendingMap;
/**
* sorting end ascending, if ends are same, sorting begin descending, so that token (end, end) will
* come before (begin, end] with the same end, and (begin, end) will be selected in the tailMap.
*/
private static final Comparator> ascendingComparator = (o1, o2) -> {
int res = o1.right.compareTo(o2.right);
if (res != 0)
return res;
return o2.left.compareTo(o1.left);
};
// ascendingMap will sort the ranges by the descending order of left token
private final NavigableMap, EndpointsForRange.Builder> descendingMap;
/**
* sorting begin descending, if begins are same, sorting end descending, so that token (begin, begin) will
* come after (begin, end] with the same begin, and (begin, end) won't be selected in the tailMap.
*/
private static final Comparator> descendingComparator = (o1, o2) -> {
int res = o2.left.compareTo(o1.left);
if (res != 0)
return res;
// if left tokens are same, sort by the descending of the right tokens.
return o2.right.compareTo(o1.right);
};
// these two maps are for warp around ranges.
private final NavigableMap, EndpointsForRange.Builder> ascendingMapForWrapAround;
/**
* for wrap around range (begin, end], which begin > end.
* Sorting end ascending, if ends are same, sorting begin ascending,
* so that token (end, end) will come before (begin, end] with the same end, and (begin, end] will be selected in
* the tailMap.
*/
private static final Comparator> ascendingComparatorForWrapAround = (o1, o2) -> {
int res = o1.right.compareTo(o2.right);
if (res != 0)
return res;
return o1.left.compareTo(o2.left);
};
private final NavigableMap, EndpointsForRange.Builder> descendingMapForWrapAround;
/**
* for wrap around ranges, which begin > end.
* Sorting end ascending, so that token (begin, begin) will come after (begin, end] with the same begin,
* and (begin, end) won't be selected in the tailMap.
*/
private static final Comparator> descendingComparatorForWrapAround = (o1, o2) -> {
int res = o2.left.compareTo(o1.left);
if (res != 0)
return res;
return o1.right.compareTo(o2.right);
};
public PendingRangeMaps()
{
this.ascendingMap = new TreeMap<>(ascendingComparator);
this.descendingMap = new TreeMap<>(descendingComparator);
this.ascendingMapForWrapAround = new TreeMap<>(ascendingComparatorForWrapAround);
this.descendingMapForWrapAround = new TreeMap<>(descendingComparatorForWrapAround);
}
static final void addToMap(Range range,
Replica replica,
NavigableMap, EndpointsForRange.Builder> ascendingMap,
NavigableMap, EndpointsForRange.Builder> descendingMap)
{
EndpointsForRange.Builder replicas = ascendingMap.get(range);
if (replicas == null)
{
replicas = new EndpointsForRange.Builder(range,1);
ascendingMap.put(range, replicas);
descendingMap.put(range, replicas);
}
replicas.add(replica, Conflict.DUPLICATE);
}
public void addPendingRange(Range range, Replica replica)
{
if (Range.isWrapAround(range.left, range.right))
{
addToMap(range, replica, ascendingMapForWrapAround, descendingMapForWrapAround);
}
else
{
addToMap(range, replica, ascendingMap, descendingMap);
}
}
static final void addIntersections(EndpointsForToken.Builder replicasToAdd,
NavigableMap, EndpointsForRange.Builder> smallerMap,
NavigableMap, EndpointsForRange.Builder> biggerMap)
{
// find the intersection of two sets
for (Range range : smallerMap.keySet())
{
EndpointsForRange.Builder replicas = biggerMap.get(range);
if (replicas != null)
{
replicasToAdd.addAll(replicas);
}
}
}
public boolean isTokenInLocalPendingRange(Token token)
{
Range searchRange = new Range<>(token, token);
// search for non-wrap-around maps
NavigableMap, EndpointsForRange.Builder> ascendingTailMap = ascendingMap.tailMap(searchRange, true);
NavigableMap, EndpointsForRange.Builder> descendingTailMap = descendingMap.tailMap(searchRange, false);
boolean ascMapSizeLTDescMapSize = ascendingTailMap.size() < descendingTailMap.size();
NavigableMap, EndpointsForRange.Builder> smallerMap = ascMapSizeLTDescMapSize ? ascendingTailMap : descendingTailMap;
NavigableMap, EndpointsForRange.Builder> biggerMap = ascMapSizeLTDescMapSize ? descendingTailMap : ascendingTailMap;
// find the intersection of two sets
for (Range range : smallerMap.keySet())
{
EndpointsForRange.Builder replicas = biggerMap.get(range);
if (replicas != null && replicas.selfIfPresent() != null)
return true;
}
// search for wrap-around sets
ascendingTailMap = ascendingMapForWrapAround.tailMap(searchRange, true);
descendingTailMap = descendingMapForWrapAround.tailMap(searchRange, false);
for (EndpointsForRange.Builder endpointsForRange : ascendingTailMap.values())
{
if (endpointsForRange.selfIfPresent() != null)
return true;
}
for (EndpointsForRange.Builder endpointsForRange : descendingTailMap.values())
{
if (endpointsForRange.selfIfPresent() != null)
return true;
}
return false;
}
public EndpointsForToken pendingEndpointsFor(Token token)
{
EndpointsForToken.Builder replicas = EndpointsForToken.builder(token);
Range searchRange = new Range<>(token, token);
// search for non-wrap-around maps
NavigableMap, EndpointsForRange.Builder> ascendingTailMap = ascendingMap.tailMap(searchRange, true);
NavigableMap, EndpointsForRange.Builder> descendingTailMap = descendingMap.tailMap(searchRange, false);
// add intersections of two maps
if (ascendingTailMap.size() < descendingTailMap.size())
{
addIntersections(replicas, ascendingTailMap, descendingTailMap);
}
else
{
addIntersections(replicas, descendingTailMap, ascendingTailMap);
}
// search for wrap-around sets
ascendingTailMap = ascendingMapForWrapAround.tailMap(searchRange, true);
descendingTailMap = descendingMapForWrapAround.tailMap(searchRange, false);
// add them since they are all necessary.
for (Map.Entry, EndpointsForRange.Builder> entry : ascendingTailMap.entrySet())
{
replicas.addAll(entry.getValue());
}
for (Map.Entry, EndpointsForRange.Builder> entry : descendingTailMap.entrySet())
{
replicas.addAll(entry.getValue());
}
return replicas.build();
}
public String printPendingRanges()
{
StringBuilder sb = new StringBuilder();
for (Map.Entry, EndpointsForRange.Builder> entry : this)
{
Range range = entry.getKey();
for (Replica replica : entry.getValue())
{
sb.append(replica).append(':').append(range);
sb.append(LINE_SEPARATOR.getString());
}
}
return sb.toString();
}
@Override
public Iterator, EndpointsForRange.Builder>> iterator()
{
return Iterators.concat(ascendingMap.entrySet().iterator(), ascendingMapForWrapAround.entrySet().iterator());
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy