mirror of https://github.com/apache/lucene.git
SOLR-6257: More than two "!"-s in a doc ID throws an ArrayIndexOutOfBoundsException when using the composite id router.
git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1611934 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
02f4d97cf9
commit
a0bc0c3d80
|
@ -196,6 +196,10 @@ Bug Fixes
|
||||||
|
|
||||||
* SOLR-6136: ConcurrentUpdateSolrServer includes a Spin Lock (Brandon Chapman, Timothy Potter)
|
* SOLR-6136: ConcurrentUpdateSolrServer includes a Spin Lock (Brandon Chapman, Timothy Potter)
|
||||||
|
|
||||||
|
* SOLR-6257: More than two "!"-s in a doc ID throws an
|
||||||
|
ArrayIndexOutOfBoundsException when using the composite id router.
|
||||||
|
(Steve Rowe)
|
||||||
|
|
||||||
Optimizations
|
Optimizations
|
||||||
---------------------
|
---------------------
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@ import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.apache.lucene.util.TestUtil;
|
||||||
import org.apache.solr.SolrTestCaseJ4;
|
import org.apache.solr.SolrTestCaseJ4;
|
||||||
import org.apache.solr.common.cloud.CompositeIdRouter;
|
import org.apache.solr.common.cloud.CompositeIdRouter;
|
||||||
import org.apache.solr.common.cloud.DocCollection;
|
import org.apache.solr.common.cloud.DocCollection;
|
||||||
|
@ -197,25 +198,73 @@ public class TestHashPartitioner extends SolrTestCaseJ4 {
|
||||||
doQuery(coll, "d/1!", "shard3,shard4"); // top bit of hash(b)==0, so shard3 and shard4
|
doQuery(coll, "d/1!", "shard3,shard4"); // top bit of hash(b)==0, so shard3 and shard4
|
||||||
}
|
}
|
||||||
|
|
||||||
/***
|
/** Make sure CompositeIdRouter doesn't throw exceptions for non-conforming IDs */
|
||||||
public void testPrintHashCodes() throws Exception {
|
public void testNonConformingCompositeIds() throws Exception {
|
||||||
// from negative to positive, the upper bits of the hash ranges should be
|
DocRouter router = DocRouter.getDocRouter(CompositeIdRouter.NAME);
|
||||||
// shard1: 11
|
DocCollection coll = createCollection(4, router);
|
||||||
// shard2: 10
|
String[] ids = { "A!B!C!D", "!!!!!!", "A!!!!B", "A!!B!!C", "A/59!B", "A/8/!B/19/",
|
||||||
// shard3: 00
|
"A!B/-5", "!/130!", "!!A/1000", "A//8!B///10!C////" };
|
||||||
// shard4: 01
|
for (int i = 0 ; i < ids.length ; ++i) {
|
||||||
|
try {
|
||||||
String[] highBitsToShard = {"shard3","shard4","shard1","shard2"};
|
Slice targetSlice = coll.getRouter().getTargetSlice(ids[i], null, null, coll);
|
||||||
|
assertNotNull(targetSlice);
|
||||||
|
} catch (Exception e) {
|
||||||
for (int i = 0; i<26; i++) {
|
throw new Exception("Exception routing id '" + ids[i] + "'", e);
|
||||||
String id = new String(Character.toChars('a'+i));
|
}
|
||||||
int hash = hash(id);
|
|
||||||
System.out.println("hash of " + id + " is " + Integer.toHexString(hash) + " high bits=" + (hash>>>30)
|
|
||||||
+ " shard="+highBitsToShard[hash>>>30]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
***/
|
|
||||||
|
/** Make sure CompositeIdRouter can route random IDs without throwing exceptions */
|
||||||
|
public void testRandomCompositeIds() throws Exception {
|
||||||
|
DocRouter router = DocRouter.getDocRouter(CompositeIdRouter.NAME);
|
||||||
|
DocCollection coll = createCollection(TestUtil.nextInt(random(), 1, 10), router);
|
||||||
|
StringBuilder idBuilder = new StringBuilder();
|
||||||
|
for (int i = 0 ; i < 10000 ; ++i) {
|
||||||
|
idBuilder.setLength(0);
|
||||||
|
int numParts = TestUtil.nextInt(random(), 1, 30);
|
||||||
|
for (int part = 0; part < numParts; ++part) {
|
||||||
|
switch (random().nextInt(5)) {
|
||||||
|
case 0: idBuilder.append('!'); break;
|
||||||
|
case 1: idBuilder.append('/'); break;
|
||||||
|
case 2: idBuilder.append(TestUtil.nextInt(random(),-100, 1000)); break;
|
||||||
|
default: {
|
||||||
|
int length = TestUtil.nextInt(random(), 1, 10);
|
||||||
|
char[] str = new char[length];
|
||||||
|
TestUtil.randomFixedLengthUnicodeString(random(), str, 0, length);
|
||||||
|
idBuilder.append(str);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
String id = idBuilder.toString();
|
||||||
|
try {
|
||||||
|
Slice targetSlice = router.getTargetSlice(id, null, null, coll);
|
||||||
|
assertNotNull(targetSlice);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new Exception("Exception routing id '" + id + "'", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/***
|
||||||
|
public void testPrintHashCodes() throws Exception {
|
||||||
|
// from negative to positive, the upper bits of the hash ranges should be
|
||||||
|
// shard1: 11
|
||||||
|
// shard2: 10
|
||||||
|
// shard3: 00
|
||||||
|
// shard4: 01
|
||||||
|
|
||||||
|
String[] highBitsToShard = {"shard3","shard4","shard1","shard2"};
|
||||||
|
|
||||||
|
|
||||||
|
for (int i = 0; i<26; i++) {
|
||||||
|
String id = new String(Character.toChars('a'+i));
|
||||||
|
int hash = hash(id);
|
||||||
|
System.out.println("hash of " + id + " is " + Integer.toHexString(hash) + " high bits=" + (hash>>>30)
|
||||||
|
+ " shard="+highBitsToShard[hash>>>30]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
***/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -187,10 +187,36 @@ public class CompositeIdRouter extends HashBasedRouter {
|
||||||
boolean triLevel;
|
boolean triLevel;
|
||||||
int pieces;
|
int pieces;
|
||||||
|
|
||||||
public KeyParser(String key) {
|
public KeyParser(final String key) {
|
||||||
String[] parts = key.split(SEPARATOR);
|
|
||||||
this.key = key;
|
this.key = key;
|
||||||
pieces = parts.length;
|
List<String> partsList = new ArrayList<>(3);
|
||||||
|
int firstSeparatorPos = key.indexOf(SEPARATOR);
|
||||||
|
if (-1 == firstSeparatorPos) {
|
||||||
|
partsList.add(key);
|
||||||
|
} else {
|
||||||
|
partsList.add(key.substring(0, firstSeparatorPos));
|
||||||
|
int lastPos = key.length() - 1;
|
||||||
|
// Don't make any more parts if the first separator is the last char
|
||||||
|
if (firstSeparatorPos < lastPos) {
|
||||||
|
int secondSeparatorPos = key.indexOf(SEPARATOR, firstSeparatorPos + 1);
|
||||||
|
if (-1 == secondSeparatorPos) {
|
||||||
|
partsList.add(key.substring(firstSeparatorPos + 1));
|
||||||
|
} else if (secondSeparatorPos == lastPos) {
|
||||||
|
// Don't make any more parts if the key has exactly two separators and
|
||||||
|
// they're the last two chars - back-compatibility with the behavior of
|
||||||
|
// String.split() - see SOLR-6257.
|
||||||
|
if (firstSeparatorPos < secondSeparatorPos - 1) {
|
||||||
|
partsList.add(key.substring(firstSeparatorPos + 1, secondSeparatorPos));
|
||||||
|
}
|
||||||
|
} else { // The second separator is not the last char
|
||||||
|
partsList.add(key.substring(firstSeparatorPos + 1, secondSeparatorPos));
|
||||||
|
partsList.add(key.substring(secondSeparatorPos + 1));
|
||||||
|
}
|
||||||
|
// Ignore any further separators beyond the first two
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pieces = partsList.size();
|
||||||
|
String[] parts = partsList.toArray(new String[pieces]);
|
||||||
numBits = new int[2];
|
numBits = new int[2];
|
||||||
if (key.endsWith("!") && pieces < 3)
|
if (key.endsWith("!") && pieces < 3)
|
||||||
pieces++;
|
pieces++;
|
||||||
|
|
Loading…
Reference in New Issue