forked from searchbox-io/Jest
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request searchbox-io#38 from tootedom/master
When Discovery is enabled, the list of servers passed to the client are not published in a thread safe manner
- Loading branch information
Showing
12 changed files
with
459 additions
and
19 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,3 +9,4 @@ target/ | |
.project | ||
.settings | ||
.classpath | ||
.DS_Store |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
162 changes: 162 additions & 0 deletions
162
src/main/java/io/searchbox/client/config/RoundRobinServerList.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,162 @@ | ||
package io.searchbox.client.config; | ||
|
||
|
||
import io.searchbox.client.config.exception.NoServerConfiguredException; | ||
import io.searchbox.client.util.PaddedAtomicInteger; | ||
|
||
import java.util.Set; | ||
import java.util.concurrent.atomic.AtomicInteger; | ||
|
||
/** | ||
* | ||
* Uses an String[] Array to loop through the given list of servers in a round robin fashion | ||
* | ||
*/ | ||
public class RoundRobinServerList implements ServerList { | ||
|
||
private final Set<String> servers; | ||
private final String[] serverList; | ||
private final int wrapPoint; | ||
private final CircularIncrement incrementer; | ||
|
||
|
||
public RoundRobinServerList(Set<String> servers) { | ||
this(servers,-1,true); | ||
} | ||
|
||
public RoundRobinServerList(Set<String> servers,boolean strictOrdering) { | ||
this(servers,-1, strictOrdering); | ||
} | ||
|
||
public RoundRobinServerList(Set<String> servers,int startAt) { | ||
this(servers,startAt, true); | ||
} | ||
|
||
public RoundRobinServerList(Set<String> servers,int startAt,boolean strictOrdering) throws NoServerConfiguredException { | ||
if(servers.size()==0) throw new NoServerConfiguredException("No Server is assigned to client to connect"); | ||
this.servers = servers; | ||
wrapPoint = servers.size(); | ||
int i =0; | ||
serverList = new String[wrapPoint]; | ||
for(String elasticSearchServer: servers) { | ||
serverList[i++] = elasticSearchServer.endsWith("/") ? | ||
elasticSearchServer.substring(0, elasticSearchServer.length() - 1) : elasticSearchServer; | ||
} | ||
|
||
int nextPowerOfTwo = ceilingNextPowerOfTwo(wrapPoint); | ||
|
||
if(nextPowerOfTwo == wrapPoint) { | ||
incrementer = new PowerOfTwoIncrement(nextPowerOfTwo,startAt); | ||
} else if(strictOrdering) { | ||
incrementer = new StrictOrderModulusIncrement(wrapPoint,startAt); | ||
} else { | ||
incrementer = new ModulusIncrement(wrapPoint,startAt); | ||
} | ||
} | ||
|
||
@Override | ||
public Set getServers() { | ||
return servers; | ||
} | ||
|
||
@Override | ||
public String getServer() { | ||
return serverList[incrementer.nextVal()]; | ||
} | ||
|
||
|
||
/** | ||
* Calculate the next power of 2, greater than or equal to x.<p> | ||
* From Hacker's Delight, Chapter 3, Harry S. Warren Jr. | ||
* | ||
* @param x Value to round up | ||
* @return The next power of 2 from x inclusive | ||
*/ | ||
public static int ceilingNextPowerOfTwo(final int x) | ||
{ | ||
return 1 << (32 - Integer.numberOfLeadingZeros(x - 1)); | ||
} | ||
|
||
private interface CircularIncrement { | ||
public int nextVal(); | ||
} | ||
|
||
/** | ||
* Uses power of two bit masking to rotate around the ring buffer of the ServerList | ||
*/ | ||
private class PowerOfTwoIncrement implements CircularIncrement { | ||
|
||
private final AtomicInteger nextPointer; | ||
|
||
private final int mask; | ||
public PowerOfTwoIncrement(int sizeOfArray, int startPosition) { | ||
nextPointer = new PaddedAtomicInteger(startPosition); | ||
mask = sizeOfArray-1; | ||
} | ||
|
||
@Override | ||
public int nextVal() { | ||
return nextPointer.incrementAndGet()&mask; | ||
} | ||
} | ||
|
||
/** | ||
* Uses modulus operator "%" to loop around the array. | ||
* When the MAX_VALUE of int has been hit, the rotation around the array will loop | ||
* until it goes back into +p've values; when it will be in order again.. i.e. | ||
* | ||
* i.e. lets say MAX_VALUE will return element 2 in the array. | ||
* MAX_VALUE+1 will return element 3 | ||
* MAX_VALUE+2 will return element 2 in the array. | ||
* MAX_VALUE+3 will return element 1 in the array | ||
*/ | ||
private class ModulusIncrement implements CircularIncrement { | ||
private final int mask; | ||
private final AtomicInteger nextPointer; | ||
|
||
|
||
public ModulusIncrement(int sizeOfArray,int startPosition) { | ||
nextPointer = new PaddedAtomicInteger(startPosition); | ||
mask = sizeOfArray; | ||
} | ||
|
||
@Override | ||
public int nextVal() { | ||
return Math.abs(nextPointer.incrementAndGet()%mask); | ||
} | ||
} | ||
|
||
/** | ||
* Uses modulus operator "%" to loop around the array. | ||
* When the MAX_VALUE of int has been hit, the rotation around the array will loop | ||
* continue in the same direction. This is done by using a CAS LOOP to set the next value | ||
* if MAX_VALUE has been reached. | ||
* | ||
*/ | ||
private class StrictOrderModulusIncrement implements CircularIncrement { | ||
private final int mask; | ||
private final AtomicInteger nextPointer; | ||
|
||
|
||
public StrictOrderModulusIncrement(int sizeOfArray,int startPosition) { | ||
nextPointer = new PaddedAtomicInteger(startPosition); | ||
mask = sizeOfArray; | ||
} | ||
|
||
@Override | ||
public int nextVal() { | ||
int currentVal; | ||
int nextVal; | ||
do { | ||
currentVal = nextPointer.get(); | ||
nextVal = currentVal+1; | ||
if(currentVal==Integer.MAX_VALUE) { | ||
int prev = ((currentVal%mask)+1); | ||
nextVal= (prev > mask) ? 0 : prev; | ||
} | ||
} while(!nextPointer.compareAndSet(currentVal,nextVal)); | ||
|
||
return nextVal%mask; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package io.searchbox.client.config; | ||
|
||
import java.util.Set; | ||
|
||
/** | ||
* Provides the interface to iterating over a set of | ||
* server addresses. | ||
*/ | ||
public interface ServerList { | ||
|
||
/** | ||
* Returns the "next" server the client should talk to. The next item is | ||
* determined by the implementation. | ||
* @return | ||
*/ | ||
public String getServer(); | ||
|
||
/** | ||
* Returns the set of servers from which the ServerList implementation | ||
* was generated. This method is only here to satisfy unit test | ||
* @return | ||
*/ | ||
public Set getServers(); | ||
|
||
} |
22 changes: 22 additions & 0 deletions
22
src/main/java/io/searchbox/client/config/exception/NoServerConfiguredException.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package io.searchbox.client.config.exception; | ||
|
||
/** | ||
* Exception that specified that the client has no | ||
* knowledge of an elasticsearch node to communicate with. | ||
* | ||
*/ | ||
public class NoServerConfiguredException extends RuntimeException { | ||
|
||
static final long serialVersionUID = -7034897190745766912L; | ||
|
||
/** | ||
* Constructs a new runtime exception with the specified detail message. | ||
* | ||
* @param message the detail message. The detail message is saved for | ||
* later retrieval by the {@link #getMessage()} method. | ||
*/ | ||
public NoServerConfiguredException(String message) { | ||
super(message); | ||
} | ||
|
||
} |
36 changes: 36 additions & 0 deletions
36
src/main/java/io/searchbox/client/util/PaddedAtomicInteger.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
/* | ||
* Copyright 2012 Real Logic Ltd. | ||
* | ||
* Licensed 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 io.searchbox.client.util; | ||
|
||
import java.util.concurrent.atomic.AtomicInteger; | ||
|
||
public class PaddedAtomicInteger extends AtomicInteger | ||
{ | ||
public PaddedAtomicInteger() | ||
{ | ||
} | ||
|
||
public PaddedAtomicInteger(final int initialValue) | ||
{ | ||
super(initialValue); | ||
} | ||
|
||
public long $sum$() { | ||
return p2 + p3 + p4 + p5 + p6 + p7; | ||
} | ||
|
||
public volatile long p1, p2, p3, p4, p5, p6, p7 = 7; | ||
} |
28 changes: 28 additions & 0 deletions
28
src/main/java/io/searchbox/client/util/PaddedAtomicReference.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
/* | ||
* Copyright (c) 2011. Peter Lawrey | ||
* | ||
* "THE BEER-WARE LICENSE" (Revision 128) | ||
* As long as you retain this notice you can do whatever you want with this stuff. | ||
* If we meet some day, and you think this stuff is worth it, you can buy me a beer in return | ||
* There is no warranty. | ||
*/ | ||
|
||
package io.searchbox.client.util; | ||
|
||
import java.util.concurrent.atomic.AtomicReference; | ||
|
||
public class PaddedAtomicReference<T> extends AtomicReference<T> { | ||
public long p2, p3, p4, p5, p6, p7; | ||
|
||
public PaddedAtomicReference() { | ||
super(); | ||
} | ||
|
||
public PaddedAtomicReference(T t) { | ||
super(t); | ||
} | ||
|
||
public long sumPadded() { | ||
return p2 + p3 + p4 + p5 + p6 + p7; | ||
} | ||
} |
Oops, something went wrong.