introduce a native int/long open immutable map, and use it in in routing table

This commit is contained in:
Shay Banon 2013-12-16 20:33:31 +01:00
parent 1dc8c079da
commit 809e870b8d
3 changed files with 679 additions and 14 deletions

View File

@ -19,6 +19,9 @@
package org.elasticsearch.cluster.routing; package org.elasticsearch.cluster.routing;
import com.carrotsearch.hppc.cursors.IntCursor;
import com.carrotsearch.hppc.cursors.IntObjectCursor;
import com.carrotsearch.hppc.cursors.LongObjectCursor;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
@ -26,6 +29,8 @@ import com.google.common.collect.UnmodifiableIterator;
import org.elasticsearch.ElasticSearchIllegalStateException; import org.elasticsearch.ElasticSearchIllegalStateException;
import org.elasticsearch.cluster.metadata.IndexMetaData; import org.elasticsearch.cluster.metadata.IndexMetaData;
import org.elasticsearch.cluster.metadata.MetaData; import org.elasticsearch.cluster.metadata.MetaData;
import org.elasticsearch.common.collect.ImmutableOpenIntMap;
import org.elasticsearch.common.collect.ImmutableOpenLongMap;
import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.index.shard.ShardId; import org.elasticsearch.index.shard.ShardId;
@ -57,20 +62,20 @@ public class IndexRoutingTable implements Iterable<IndexShardRoutingTable> {
// note, we assume that when the index routing is created, ShardRoutings are created for all possible number of // note, we assume that when the index routing is created, ShardRoutings are created for all possible number of
// shards with state set to UNASSIGNED // shards with state set to UNASSIGNED
private final ImmutableMap<Integer, IndexShardRoutingTable> shards; private final ImmutableOpenIntMap<IndexShardRoutingTable> shards;
private final ImmutableList<ShardRouting> allShards; private final ImmutableList<ShardRouting> allShards;
private final ImmutableList<ShardRouting> allActiveShards; private final ImmutableList<ShardRouting> allActiveShards;
private final AtomicInteger counter = new AtomicInteger(); private final AtomicInteger counter = new AtomicInteger();
IndexRoutingTable(String index, Map<Integer, IndexShardRoutingTable> shards) { IndexRoutingTable(String index, ImmutableOpenIntMap<IndexShardRoutingTable> shards) {
this.index = index; this.index = index;
this.shards = ImmutableMap.copyOf(shards); this.shards = shards;
ImmutableList.Builder<ShardRouting> allShards = ImmutableList.builder(); ImmutableList.Builder<ShardRouting> allShards = ImmutableList.builder();
ImmutableList.Builder<ShardRouting> allActiveShards = ImmutableList.builder(); ImmutableList.Builder<ShardRouting> allActiveShards = ImmutableList.builder();
for (IndexShardRoutingTable indexShardRoutingTable : shards.values()) { for (IntObjectCursor<IndexShardRoutingTable> cursor : shards) {
for (ShardRouting shardRouting : indexShardRoutingTable) { for (ShardRouting shardRouting : cursor.value) {
allShards.add(shardRouting); allShards.add(shardRouting);
if (shardRouting.active()) { if (shardRouting.active()) {
allActiveShards.add(shardRouting); allActiveShards.add(shardRouting);
@ -107,8 +112,8 @@ public class IndexRoutingTable implements Iterable<IndexShardRoutingTable> {
*/ */
public IndexRoutingTable normalizeVersions() { public IndexRoutingTable normalizeVersions() {
IndexRoutingTable.Builder builder = new Builder(this.index); IndexRoutingTable.Builder builder = new Builder(this.index);
for (IndexShardRoutingTable shardTable : shards.values()) { for (IntObjectCursor<IndexShardRoutingTable> cursor : shards) {
builder.addIndexShard(shardTable.normalizeVersions()); builder.addIndexShard(cursor.value.normalizeVersions());
} }
return builder.build(); return builder.build();
} }
@ -147,7 +152,7 @@ public class IndexRoutingTable implements Iterable<IndexShardRoutingTable> {
@Override @Override
public UnmodifiableIterator<IndexShardRoutingTable> iterator() { public UnmodifiableIterator<IndexShardRoutingTable> iterator() {
return shards.values().iterator(); return shards.valuesIt();
} }
/** /**
@ -182,11 +187,11 @@ public class IndexRoutingTable implements Iterable<IndexShardRoutingTable> {
return nodes.size(); return nodes.size();
} }
public ImmutableMap<Integer, IndexShardRoutingTable> shards() { public ImmutableOpenIntMap<IndexShardRoutingTable> shards() {
return shards; return shards;
} }
public ImmutableMap<Integer, IndexShardRoutingTable> getShards() { public ImmutableOpenIntMap<IndexShardRoutingTable> getShards() {
return shards(); return shards();
} }
@ -307,7 +312,7 @@ public class IndexRoutingTable implements Iterable<IndexShardRoutingTable> {
public static class Builder { public static class Builder {
private final String index; private final String index;
private final Map<Integer, IndexShardRoutingTable> shards = new HashMap<Integer, IndexShardRoutingTable>(); private final ImmutableOpenIntMap.Builder<IndexShardRoutingTable> shards = ImmutableOpenIntMap.builder();
public Builder(String index) { public Builder(String index) {
this.index = index; this.index = index;
@ -410,7 +415,8 @@ public class IndexRoutingTable implements Iterable<IndexShardRoutingTable> {
} }
public Builder addReplica() { public Builder addReplica() {
for (int shardId : shards.keySet()) { for (IntCursor cursor : shards.keys()) {
int shardId = cursor.value;
// version 0, will get updated when reroute will happen // version 0, will get updated when reroute will happen
ImmutableShardRouting shard = new ImmutableShardRouting(index, shardId, null, false, ShardRoutingState.UNASSIGNED, 0); ImmutableShardRouting shard = new ImmutableShardRouting(index, shardId, null, false, ShardRoutingState.UNASSIGNED, 0);
shards.put(shardId, shards.put(shardId,
@ -421,7 +427,8 @@ public class IndexRoutingTable implements Iterable<IndexShardRoutingTable> {
} }
public Builder removeReplica() { public Builder removeReplica() {
for (int shardId : shards.keySet()) { for (IntCursor cursor : shards.keys()) {
int shardId = cursor.value;
IndexShardRoutingTable indexShard = shards.get(shardId); IndexShardRoutingTable indexShard = shards.get(shardId);
if (indexShard.replicaShards().isEmpty()) { if (indexShard.replicaShards().isEmpty()) {
// nothing to do here! // nothing to do here!
@ -486,7 +493,7 @@ public class IndexRoutingTable implements Iterable<IndexShardRoutingTable> {
} }
public IndexRoutingTable build() throws RoutingValidationException { public IndexRoutingTable build() throws RoutingValidationException {
IndexRoutingTable indexRoutingTable = new IndexRoutingTable(index, ImmutableMap.copyOf(shards)); IndexRoutingTable indexRoutingTable = new IndexRoutingTable(index, shards.build());
indexRoutingTable.validate(); indexRoutingTable.validate();
return indexRoutingTable; return indexRoutingTable;
} }

View File

@ -0,0 +1,329 @@
/*
* Licensed to ElasticSearch and Shay Banon under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. ElasticSearch 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.elasticsearch.common.collect;
import com.carrotsearch.hppc.*;
import com.carrotsearch.hppc.cursors.IntCursor;
import com.carrotsearch.hppc.cursors.IntObjectCursor;
import com.carrotsearch.hppc.cursors.ObjectCursor;
import com.carrotsearch.hppc.predicates.IntPredicate;
import com.carrotsearch.hppc.procedures.IntObjectProcedure;
import com.google.common.collect.UnmodifiableIterator;
import java.util.Iterator;
import java.util.Map;
/**
* An immutable map implementation based on open hash map.
* <p/>
* Can be constructed using a {@link #builder()}, or using {@link #builder(org.elasticsearch.common.collect.ImmutableOpenIntMap)} (which is an optimized
* option to copy over existing content and modify it).
*/
public final class ImmutableOpenIntMap<VType> implements Iterable<IntObjectCursor<VType>> {
private final IntObjectOpenHashMap<VType> map;
private ImmutableOpenIntMap(IntObjectOpenHashMap<VType> map) {
this.map = map;
}
/**
* @return Returns the value associated with the given key or the default value
* for the key type, if the key is not associated with any value.
* <p/>
* <b>Important note:</b> For primitive type values, the value returned for a non-existing
* key may not be the default value of the primitive type (it may be any value previously
* assigned to that slot).
*/
public VType get(int key) {
return map.get(key);
}
/**
* Returns <code>true</code> if this container has an association to a value for
* the given key.
*/
public boolean containsKey(int key) {
return map.containsKey(key);
}
/**
* @return Returns the current size (number of assigned keys) in the container.
*/
public int size() {
return map.size();
}
/**
* @return Return <code>true</code> if this hash map contains no assigned keys.
*/
public boolean isEmpty() {
return map.isEmpty();
}
/**
* Returns a cursor over the entries (key-value pairs) in this map. The iterator is
* implemented as a cursor and it returns <b>the same cursor instance</b> on every
* call to {@link java.util.Iterator#next()}. To read the current key and value use the cursor's
* public fields. An example is shown below.
* <pre>
* for (IntShortCursor c : intShortMap)
* {
* System.out.println(&quot;index=&quot; + c.index
* + &quot; key=&quot; + c.key
* + &quot; value=&quot; + c.value);
* }
* </pre>
* <p/>
* <p>The <code>index</code> field inside the cursor gives the internal index inside
* the container's implementation. The interpretation of this index depends on
* to the container.
*/
@Override
public Iterator<IntObjectCursor<VType>> iterator() {
return map.iterator();
}
/**
* Returns a specialized view of the keys of this associated container.
* The view additionally implements {@link com.carrotsearch.hppc.ObjectLookupContainer}.
*/
public IntLookupContainer keys() {
return map.keys();
}
/**
* Returns a direct iterator over the keys.
*/
public UnmodifiableIterator<Integer> keysIt() {
final Iterator<IntCursor> iterator = map.keys().iterator();
return new UnmodifiableIterator<Integer>() {
@Override
public boolean hasNext() {
return iterator.hasNext();
}
@Override
public Integer next() {
return iterator.next().value;
}
};
}
/**
* @return Returns a container with all values stored in this map.
*/
public ObjectContainer<VType> values() {
return map.values();
}
/**
* Returns a direct iterator over the keys.
*/
public UnmodifiableIterator<VType> valuesIt() {
final Iterator<ObjectCursor<VType>> iterator = map.values().iterator();
return new UnmodifiableIterator<VType>() {
@Override
public boolean hasNext() {
return iterator.hasNext();
}
@Override
public VType next() {
return iterator.next().value;
}
};
}
@Override
public String toString() {
return map.toString();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ImmutableOpenIntMap that = (ImmutableOpenIntMap) o;
if (!map.equals(that.map)) return false;
return true;
}
@Override
public int hashCode() {
return map.hashCode();
}
@SuppressWarnings("unchecked")
private static final ImmutableOpenIntMap EMPTY = new ImmutableOpenIntMap(new IntObjectOpenHashMap());
@SuppressWarnings("unchecked")
public static <VType> ImmutableOpenIntMap<VType> of() {
return EMPTY;
}
public static <VType> Builder<VType> builder() {
return new Builder<VType>();
}
public static <VType> Builder<VType> builder(int size) {
return new Builder<VType>(size);
}
public static <VType> Builder<VType> builder(ImmutableOpenIntMap<VType> map) {
return new Builder<VType>(map);
}
public static class Builder<VType> implements IntObjectMap<VType> {
private IntObjectOpenHashMap<VType> map;
public Builder() {
//noinspection unchecked
this(EMPTY);
}
public Builder(int size) {
this.map = new IntObjectOpenHashMap<VType>(size);
}
public Builder(ImmutableOpenIntMap<VType> map) {
this.map = map.map.clone();
}
/**
* Builds a new instance of the
*/
public ImmutableOpenIntMap<VType> build() {
IntObjectOpenHashMap<VType> map = this.map;
this.map = null; // nullify the map, so any operation post build will fail! (hackish, but safest)
return new ImmutableOpenIntMap<VType>(map);
}
/**
* Puts all the entries in the map to the builder.
*/
public Builder<VType> putAll(Map<Integer, VType> map) {
for (Map.Entry<Integer, VType> entry : map.entrySet()) {
this.map.put(entry.getKey(), entry.getValue());
}
return this;
}
/**
* A put operation that can be used in the fluent pattern.
*/
public Builder<VType> fPut(int key, VType value) {
map.put(key, value);
return this;
}
@Override
public VType put(int key, VType value) {
return map.put(key, value);
}
@Override
public VType get(int key) {
return map.get(key);
}
@Override
public VType getOrDefault(int kType, VType vType) {
return map.getOrDefault(kType, vType);
}
/**
* Remove that can be used in the fluent pattern.
*/
public Builder<VType> fRemove(int key) {
map.remove(key);
return this;
}
@Override
public VType remove(int key) {
return map.remove(key);
}
@Override
public Iterator<IntObjectCursor<VType>> iterator() {
return map.iterator();
}
@Override
public boolean containsKey(int key) {
return map.containsKey(key);
}
@Override
public int size() {
return map.size();
}
@Override
public boolean isEmpty() {
return map.isEmpty();
}
@Override
public void clear() {
map.clear();
}
@Override
public int putAll(IntObjectAssociativeContainer<? extends VType> container) {
return map.putAll(container);
}
@Override
public int putAll(Iterable<? extends IntObjectCursor<? extends VType>> iterable) {
return map.putAll(iterable);
}
@Override
public int removeAll(IntContainer container) {
return map.removeAll(container);
}
@Override
public int removeAll(IntPredicate predicate) {
return map.removeAll(predicate);
}
@Override
public <T extends IntObjectProcedure<? super VType>> T forEach(T procedure) {
return map.forEach(procedure);
}
@Override
public IntCollection keys() {
return map.keys();
}
@Override
public ObjectContainer<VType> values() {
return map.values();
}
}
}

View File

@ -0,0 +1,329 @@
/*
* Licensed to ElasticSearch and Shay Banon under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. ElasticSearch 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.elasticsearch.common.collect;
import com.carrotsearch.hppc.*;
import com.carrotsearch.hppc.cursors.LongCursor;
import com.carrotsearch.hppc.cursors.LongObjectCursor;
import com.carrotsearch.hppc.cursors.ObjectCursor;
import com.carrotsearch.hppc.predicates.LongPredicate;
import com.carrotsearch.hppc.procedures.LongObjectProcedure;
import com.google.common.collect.UnmodifiableIterator;
import java.util.Iterator;
import java.util.Map;
/**
* An immutable map implementation based on open hash map.
* <p/>
* Can be constructed using a {@link #builder()}, or using {@link #builder(org.elasticsearch.common.collect.ImmutableOpenLongMap)} (which is an optimized
* option to copy over existing content and modify it).
*/
public final class ImmutableOpenLongMap<VType> implements Iterable<LongObjectCursor<VType>> {
private final LongObjectOpenHashMap<VType> map;
private ImmutableOpenLongMap(LongObjectOpenHashMap<VType> map) {
this.map = map;
}
/**
* @return Returns the value associated with the given key or the default value
* for the key type, if the key is not associated with any value.
* <p/>
* <b>Important note:</b> For primitive type values, the value returned for a non-existing
* key may not be the default value of the primitive type (it may be any value previously
* assigned to that slot).
*/
public VType get(long key) {
return map.get(key);
}
/**
* Returns <code>true</code> if this container has an association to a value for
* the given key.
*/
public boolean containsKey(long key) {
return map.containsKey(key);
}
/**
* @return Returns the current size (number of assigned keys) in the container.
*/
public int size() {
return map.size();
}
/**
* @return Return <code>true</code> if this hash map contains no assigned keys.
*/
public boolean isEmpty() {
return map.isEmpty();
}
/**
* Returns a cursor over the entries (key-value pairs) in this map. The iterator is
* implemented as a cursor and it returns <b>the same cursor instance</b> on every
* call to {@link java.util.Iterator#next()}. To read the current key and value use the cursor's
* public fields. An example is shown below.
* <pre>
* for (IntShortCursor c : intShortMap)
* {
* System.out.println(&quot;index=&quot; + c.index
* + &quot; key=&quot; + c.key
* + &quot; value=&quot; + c.value);
* }
* </pre>
* <p/>
* <p>The <code>index</code> field inside the cursor gives the internal index inside
* the container's implementation. The interpretation of this index depends on
* to the container.
*/
@Override
public Iterator<LongObjectCursor<VType>> iterator() {
return map.iterator();
}
/**
* Returns a specialized view of the keys of this associated container.
* The view additionally implements {@link com.carrotsearch.hppc.ObjectLookupContainer}.
*/
public LongLookupContainer keys() {
return map.keys();
}
/**
* Returns a direct iterator over the keys.
*/
public UnmodifiableIterator<Long> keysIt() {
final Iterator<LongCursor> iterator = map.keys().iterator();
return new UnmodifiableIterator<Long>() {
@Override
public boolean hasNext() {
return iterator.hasNext();
}
@Override
public Long next() {
return iterator.next().value;
}
};
}
/**
* @return Returns a container with all values stored in this map.
*/
public ObjectContainer<VType> values() {
return map.values();
}
/**
* Returns a direct iterator over the keys.
*/
public UnmodifiableIterator<VType> valuesIt() {
final Iterator<ObjectCursor<VType>> iterator = map.values().iterator();
return new UnmodifiableIterator<VType>() {
@Override
public boolean hasNext() {
return iterator.hasNext();
}
@Override
public VType next() {
return iterator.next().value;
}
};
}
@Override
public String toString() {
return map.toString();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ImmutableOpenLongMap that = (ImmutableOpenLongMap) o;
if (!map.equals(that.map)) return false;
return true;
}
@Override
public int hashCode() {
return map.hashCode();
}
@SuppressWarnings("unchecked")
private static final ImmutableOpenLongMap EMPTY = new ImmutableOpenLongMap(new LongObjectOpenHashMap());
@SuppressWarnings("unchecked")
public static <VType> ImmutableOpenLongMap<VType> of() {
return EMPTY;
}
public static <VType> Builder<VType> builder() {
return new Builder<VType>();
}
public static <VType> Builder<VType> builder(int size) {
return new Builder<VType>(size);
}
public static <VType> Builder<VType> builder(ImmutableOpenLongMap<VType> map) {
return new Builder<VType>(map);
}
public static class Builder<VType> implements LongObjectMap<VType> {
private LongObjectOpenHashMap<VType> map;
public Builder() {
//noinspection unchecked
this(EMPTY);
}
public Builder(int size) {
this.map = new LongObjectOpenHashMap<VType>(size);
}
public Builder(ImmutableOpenLongMap<VType> map) {
this.map = map.map.clone();
}
/**
* Builds a new instance of the
*/
public ImmutableOpenLongMap<VType> build() {
LongObjectOpenHashMap<VType> map = this.map;
this.map = null; // nullify the map, so any operation post build will fail! (hackish, but safest)
return new ImmutableOpenLongMap<VType>(map);
}
/**
* Puts all the entries in the map to the builder.
*/
public Builder<VType> putAll(Map<Long, VType> map) {
for (Map.Entry<Long, VType> entry : map.entrySet()) {
this.map.put(entry.getKey(), entry.getValue());
}
return this;
}
/**
* A put operation that can be used in the fluent pattern.
*/
public Builder<VType> fPut(long key, VType value) {
map.put(key, value);
return this;
}
@Override
public VType put(long key, VType value) {
return map.put(key, value);
}
@Override
public VType get(long key) {
return map.get(key);
}
@Override
public VType getOrDefault(long kType, VType vType) {
return map.getOrDefault(kType, vType);
}
/**
* Remove that can be used in the fluent pattern.
*/
public Builder<VType> fRemove(long key) {
map.remove(key);
return this;
}
@Override
public VType remove(long key) {
return map.remove(key);
}
@Override
public Iterator<LongObjectCursor<VType>> iterator() {
return map.iterator();
}
@Override
public boolean containsKey(long key) {
return map.containsKey(key);
}
@Override
public int size() {
return map.size();
}
@Override
public boolean isEmpty() {
return map.isEmpty();
}
@Override
public void clear() {
map.clear();
}
@Override
public int putAll(LongObjectAssociativeContainer<? extends VType> container) {
return map.putAll(container);
}
@Override
public int putAll(Iterable<? extends LongObjectCursor<? extends VType>> iterable) {
return map.putAll(iterable);
}
@Override
public int removeAll(LongContainer container) {
return map.removeAll(container);
}
@Override
public int removeAll(LongPredicate predicate) {
return map.removeAll(predicate);
}
@Override
public <T extends LongObjectProcedure<? super VType>> T forEach(T procedure) {
return map.forEach(procedure);
}
@Override
public LongCollection keys() {
return map.keys();
}
@Override
public ObjectContainer<VType> values() {
return map.values();
}
}
}