Be more careful with RoutingTable.Builder

RoutingTable.Builder#build can only be called once but didn't have any
checks to make sure it _was_ only called once. And the error message it
threw when called more than once was a NullPointerException. This makes
it throw IllegalStateException when you try to reuse the builder in any way.
This commit is contained in:
Nik Everett 2015-10-09 10:28:13 -04:00
parent bfb9054a11
commit 56318df10c
2 changed files with 54 additions and 5 deletions

View File

@ -350,7 +350,7 @@ public class RoutingTable implements Iterable<IndexRoutingTable>, Diffable<Routi
public static class Builder {
private long version;
private final ImmutableOpenMap.Builder<String, IndexRoutingTable> indicesRouting = ImmutableOpenMap.builder();
private ImmutableOpenMap.Builder<String, IndexRoutingTable> indicesRouting = ImmutableOpenMap.builder();
public Builder() {
@ -406,6 +406,9 @@ public class RoutingTable implements Iterable<IndexRoutingTable>, Diffable<Routi
}
public Builder updateNumberOfReplicas(int numberOfReplicas, String... indices) {
if (indicesRouting == null) {
throw new IllegalStateException("once build is called the builder cannot be reused");
}
if (indices == null || indices.length == 0) {
indices = indicesRouting.keys().toArray(String.class);
}
@ -492,6 +495,9 @@ public class RoutingTable implements Iterable<IndexRoutingTable>, Diffable<Routi
}
public Builder add(IndexRoutingTable indexRoutingTable) {
if (indicesRouting == null) {
throw new IllegalStateException("once build is called the builder cannot be reused");
}
indexRoutingTable.validate();
indicesRouting.put(indexRoutingTable.index(), indexRoutingTable);
return this;
@ -503,11 +509,17 @@ public class RoutingTable implements Iterable<IndexRoutingTable>, Diffable<Routi
}
public Builder indicesRouting(Map<String, IndexRoutingTable> indicesRouting) {
if (indicesRouting == null) {
throw new IllegalStateException("once build is called the builder cannot be reused");
}
this.indicesRouting.putAll(indicesRouting);
return this;
}
public Builder remove(String index) {
if (indicesRouting == null) {
throw new IllegalStateException("once build is called the builder cannot be reused");
}
indicesRouting.remove(index);
return this;
}
@ -518,16 +530,21 @@ public class RoutingTable implements Iterable<IndexRoutingTable>, Diffable<Routi
}
/**
* Builds the routing table. Note that this can only be called one time.
* If you need to build a new RoutingTable as a copy of this one you'll
* need to build a new RoutingTable.Builder.
* Builds the routing table. Note that once this is called the builder
* must be thrown away. If you need to build a new RoutingTable as a
* copy of this one you'll need to build a new RoutingTable.Builder.
*/
public RoutingTable build() {
if (indicesRouting == null) {
throw new IllegalStateException("once build is called the builder cannot be reused");
}
// normalize the versions right before we build it...
for (ObjectCursor<IndexRoutingTable> indexRoutingTable : indicesRouting.values()) {
indicesRouting.put(indexRoutingTable.value.index(), indexRoutingTable.value.normalizeVersions());
}
return new RoutingTable(version, indicesRouting.build());
RoutingTable table = new RoutingTable(version, indicesRouting.build());
indicesRouting = null;
return table;
}
public static RoutingTable readFrom(StreamInput in) throws IOException {

View File

@ -35,6 +35,7 @@ import org.junit.Test;
import static org.elasticsearch.cluster.routing.ShardRoutingState.INITIALIZING;
import static org.elasticsearch.common.settings.Settings.settingsBuilder;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.nullValue;
@ -55,6 +56,7 @@ public class RoutingTableTests extends ESAllocationTestCase {
.build());
private ClusterState clusterState;
@Override
@Before
public void setUp() throws Exception {
super.setUp();
@ -264,4 +266,34 @@ public class RoutingTableTests extends ESAllocationTestCase {
fail("Calling with non-existing index should be ignored at the moment");
}
}
public void testRoutingTableBuiltMoreThanOnce() {
RoutingTable.Builder b = RoutingTable.builder();
b.build(); // Ok the first time
try {
b.build();
fail("expected exception");
} catch (IllegalStateException e) {
assertThat(e.getMessage(), containsString("cannot be reused"));
}
try {
b.add((IndexRoutingTable) null);
fail("expected exception");
} catch (IllegalStateException e) {
assertThat(e.getMessage(), containsString("cannot be reused"));
}
try {
b.updateNumberOfReplicas(1, "foo");
fail("expected exception");
} catch (IllegalStateException e) {
assertThat(e.getMessage(), containsString("cannot be reused"));
}
try {
b.remove("foo");
fail("expected exception");
} catch (IllegalStateException e) {
assertThat(e.getMessage(), containsString("cannot be reused"));
}
}
}