mirror of https://github.com/apache/lucene.git
SOLR-10278: conditions tested
This commit is contained in:
parent
6373aeea36
commit
bec41550db
|
@ -26,17 +26,25 @@ import java.util.Set;
|
|||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import org.apache.solr.common.MapWriter;
|
||||
import org.apache.solr.common.params.CommonParams;
|
||||
import org.apache.solr.common.util.Utils;
|
||||
import org.apache.solr.recipe.RuleSorter.ReplicaStat;
|
||||
import org.apache.solr.recipe.RuleSorter.Row;
|
||||
|
||||
import static java.util.Collections.singletonMap;
|
||||
import static org.apache.solr.common.params.CoreAdminParams.COLLECTION;
|
||||
import static org.apache.solr.common.params.CoreAdminParams.REPLICA;
|
||||
import static org.apache.solr.common.params.CoreAdminParams.SHARD;
|
||||
import static org.apache.solr.recipe.Clause.TestStatus.FAIL;
|
||||
import static org.apache.solr.recipe.Clause.TestStatus.NOT_APPLICABLE;
|
||||
import static org.apache.solr.recipe.Clause.TestStatus.PASS;
|
||||
import static org.apache.solr.recipe.Operand.EQUAL;
|
||||
import static org.apache.solr.recipe.Operand.GREATER_THAN;
|
||||
import static org.apache.solr.recipe.Operand.LESS_THAN;
|
||||
import static org.apache.solr.recipe.Operand.NOT_EQUAL;
|
||||
import static org.apache.solr.recipe.Operand.WILDCARD;
|
||||
import static org.apache.solr.recipe.RuleSorter.ANY;
|
||||
import static org.apache.solr.recipe.RuleSorter.EACH;
|
||||
|
||||
|
||||
public class Clause implements MapWriter {
|
||||
|
@ -74,12 +82,18 @@ public class Clause implements MapWriter {
|
|||
this.op = op;
|
||||
}
|
||||
|
||||
boolean isMatch(Row row) {
|
||||
return op.canMatch(val, row.getVal(name));
|
||||
TestStatus match(Row row) {
|
||||
return op.match(val, row.getVal(name));
|
||||
}
|
||||
boolean isMatch(Object inputVal) {
|
||||
return op.canMatch(val, inputVal);
|
||||
|
||||
boolean isPass(Object inputVal) {
|
||||
return op.match(val, inputVal) == PASS;
|
||||
}
|
||||
|
||||
boolean isPass(Row row) {
|
||||
return op.match(val, row.getVal(name)) == PASS;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Condition parse(String s, Map m) {
|
||||
|
@ -89,8 +103,8 @@ public class Clause implements MapWriter {
|
|||
String conditionName = s.trim();
|
||||
String value = val == null ? null : String.valueOf(val).trim();
|
||||
Operand operand = null;
|
||||
if ((expectedVal = Operand.ANY.parse(value)) != null) {
|
||||
operand = Operand.ANY;
|
||||
if ((expectedVal = WILDCARD.parse(value)) != null) {
|
||||
operand = WILDCARD;
|
||||
} else if ((expectedVal = NOT_EQUAL.parse(value)) != null) {
|
||||
operand = NOT_EQUAL;
|
||||
} else if ((expectedVal = GREATER_THAN.parse(value)) != null) {
|
||||
|
@ -111,26 +125,36 @@ public class Clause implements MapWriter {
|
|||
|
||||
|
||||
TestStatus test(Row row) {
|
||||
AtomicReference<TestStatus> result = new AtomicReference<>(TestStatus.NOT_APPLICABLE);
|
||||
outer:
|
||||
for (Map.Entry<String, Map<String, List<RuleSorter.ReplicaStat>>> e : row.replicaInfo.entrySet()) {
|
||||
if (!collection.isMatch(e.getKey())) break;
|
||||
AtomicReference<TestStatus> result = new AtomicReference<>(NOT_APPLICABLE);
|
||||
|
||||
for (Map.Entry<String, Map<String, List<ReplicaStat>>> colls : row.replicaInfo.entrySet()) {
|
||||
if (!collection.isPass(colls.getKey()) || result.get() == FAIL) break;
|
||||
int count = 0;
|
||||
for (Map.Entry<String, List<RuleSorter.ReplicaStat>> e1 : e.getValue().entrySet()) {
|
||||
if (!shard.isMatch(e1.getKey())) break;
|
||||
count += e1.getValue().size();
|
||||
if (shard.val.equals(RuleSorter.EACH) && count > 0 && replica.isMatch(count) && tag.isMatch(row)) {
|
||||
result.set(TestStatus.FAIL);
|
||||
continue outer;
|
||||
for (Map.Entry<String, List<ReplicaStat>> shards : colls.getValue().entrySet()) {
|
||||
if (!shard.isPass(shards.getKey()) || result.get() == FAIL) break;
|
||||
count += shards.getValue().size();
|
||||
if (shard.val.equals(EACH)) testReplicaCount(row, result, count);
|
||||
if (EACH.equals(shard.val)) count = 0;
|
||||
}
|
||||
if (RuleSorter.EACH.equals(shard.val)) count = 0;
|
||||
if (shard.val.equals(ANY)) testReplicaCount(row, result, count);
|
||||
}
|
||||
if (shard.val.equals(RuleSorter.ANY) && count > 0 && replica.isMatch(count) && !tag.isMatch(row)) {
|
||||
result.set(TestStatus.FAIL);
|
||||
if (result.get() == FAIL) row.violations.add(this);
|
||||
return result.get();
|
||||
|
||||
}
|
||||
|
||||
private void testReplicaCount(Row row, AtomicReference<TestStatus> result, int count) {
|
||||
if("node".equals(tag.name)) if(!tag.isPass(row.node)) return;
|
||||
boolean checkCount = replica.op.match(replica.val, 0) != PASS || count > 0;
|
||||
if (replica.op == WILDCARD && count > 0 && !tag.isPass(row)) {
|
||||
result.set(FAIL);
|
||||
} else if (checkCount && !replica.isPass(count)) {
|
||||
if (tag.op != WILDCARD && tag.isPass(row)) {
|
||||
result.set(FAIL);
|
||||
} else {
|
||||
result.set(FAIL);
|
||||
}
|
||||
}
|
||||
if (result.get() == TestStatus.FAIL) row.violations.add(this);
|
||||
return result.get();
|
||||
}
|
||||
|
||||
public boolean isStrict() {
|
||||
|
|
|
@ -19,25 +19,29 @@ package org.apache.solr.recipe;
|
|||
|
||||
import java.util.Objects;
|
||||
|
||||
import org.apache.solr.recipe.Clause.TestStatus;
|
||||
import static org.apache.solr.recipe.Clause.TestStatus.*;
|
||||
import static org.apache.solr.recipe.RuleSorter.ANY;
|
||||
|
||||
|
||||
public enum Operand {
|
||||
ANY(""){
|
||||
WILDCARD(ANY){
|
||||
@Override
|
||||
public boolean canMatch(Object ruleVal, Object testVal) {
|
||||
return true;
|
||||
public TestStatus match(Object ruleVal, Object testVal) {
|
||||
return testVal == null ? NOT_APPLICABLE : PASS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object parse(String val) {
|
||||
if(val == null) return RuleSorter.ANY;
|
||||
return RuleSorter.ANY.equals(val) || RuleSorter.EACH.equals(val) ? val : null;
|
||||
if(val == null) return ANY;
|
||||
return ANY.equals(val) || RuleSorter.EACH.equals(val) ? val : null;
|
||||
}
|
||||
},
|
||||
EQUAL(""),
|
||||
NOT_EQUAL("!") {
|
||||
@Override
|
||||
public boolean canMatch(Object ruleVal, Object testVal) {
|
||||
return !super.canMatch(ruleVal, testVal);
|
||||
public TestStatus match(Object ruleVal, Object testVal) {
|
||||
return super.match(ruleVal, testVal) == PASS ? FAIL : PASS;
|
||||
}
|
||||
},
|
||||
GREATER_THAN(">") {
|
||||
|
@ -48,16 +52,18 @@ public enum Operand {
|
|||
|
||||
|
||||
@Override
|
||||
public boolean canMatch(Object ruleVal, Object testVal) {
|
||||
return testVal != null && compareNum(ruleVal, testVal) == -1;
|
||||
public TestStatus match(Object ruleVal, Object testVal) {
|
||||
if (testVal == null) return NOT_APPLICABLE;
|
||||
return compareNum(ruleVal, testVal) == 1 ? PASS : FAIL;
|
||||
}
|
||||
|
||||
},
|
||||
LESS_THAN("<") {
|
||||
|
||||
@Override
|
||||
public boolean canMatch(Object ruleVal, Object testVal) {
|
||||
return testVal != null && compareNum(ruleVal, testVal) != -1;
|
||||
public TestStatus match(Object ruleVal, Object testVal) {
|
||||
if (testVal == null) return NOT_APPLICABLE;
|
||||
return compareNum(ruleVal, testVal) == -1 ? PASS : FAIL;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -89,8 +95,8 @@ public enum Operand {
|
|||
return val.startsWith(operand) ? val.substring(1) : null;
|
||||
}
|
||||
|
||||
public boolean canMatch(Object ruleVal, Object testVal) {
|
||||
return Objects.equals(String.valueOf(ruleVal), String.valueOf(testVal));
|
||||
public TestStatus match(Object ruleVal, Object testVal) {
|
||||
return Objects.equals(String.valueOf(ruleVal), String.valueOf(testVal)) ? PASS : FAIL;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -238,6 +238,11 @@ public class RuleSorter {
|
|||
for (Cell cell : cells) if (cell.name.equals(name)) return cell.val;
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
||||
static class Cell implements MapWriter {
|
||||
|
|
|
@ -32,9 +32,27 @@ import org.apache.solr.common.util.Utils;
|
|||
import org.apache.solr.common.util.ValidatingJsonMap;
|
||||
|
||||
public class TestRuleSorter extends SolrTestCaseJ4 {
|
||||
|
||||
public void testOperands() {
|
||||
Clause c = new Clause((Map<String, Object>) Utils.fromJSONString("{replica:'<2', node:'#ANY'}"));
|
||||
assertFalse(c.replica.isPass(3));
|
||||
assertFalse(c.replica.isPass(2));
|
||||
assertTrue(c.replica.isPass(1));
|
||||
|
||||
c = new Clause((Map<String, Object>) Utils.fromJSONString("{replica:'>2', node:'#ANY'}"));
|
||||
assertTrue(c.replica.isPass(3));
|
||||
assertFalse(c.replica.isPass(2));
|
||||
assertFalse(c.replica.isPass(1));
|
||||
|
||||
c = new Clause((Map<String, Object>) Utils.fromJSONString("{nodeRole:'!overseer'}"));
|
||||
assertTrue(c.tag.isPass("OVERSEER"));
|
||||
assertFalse(c.tag.isPass("overseer"));
|
||||
|
||||
|
||||
}
|
||||
public void testRuleParsing() throws IOException {
|
||||
String rules = "{" +
|
||||
"conditions:[{nodeRole:'!overseer', strict:false}, " +
|
||||
"conditions:[{nodeRole:'!overseer', strict:false},{replica:'<1',node:node3}," +
|
||||
"{replica:'<2',node:'#ANY', shard:'#EACH'}]," +
|
||||
" preferences:[" +
|
||||
"{minimize:cores , precision:2}," +
|
||||
|
@ -46,38 +64,46 @@ public class TestRuleSorter extends SolrTestCaseJ4 {
|
|||
"node1:{cores:12, freedisk: 334, heap:10480}," +
|
||||
"node2:{cores:4, freedisk: 749, heap:6873}," +
|
||||
"node3:{cores:7, freedisk: 262, heap:7834}," +
|
||||
"node4:{cores:8, freedisk: 375, heap:16900}" +
|
||||
"node4:{cores:8, freedisk: 375, heap:16900, nodeRole:overseer}" +
|
||||
"}");
|
||||
String clusterState = "{'gettingstarted':{" +
|
||||
" 'router':{'name':'compositeId'}," +
|
||||
" 'shards':{" +
|
||||
" 'shard1':{" +
|
||||
" 'range':'80000000-ffffffff'," +
|
||||
" 'state':'active'," +
|
||||
" 'replicas':{" +
|
||||
" 'core_node1':{" +
|
||||
" 'core':'gettingstarted_shard1_replica1'," +
|
||||
" 'r1':{" +
|
||||
" 'core':r1," +
|
||||
" 'base_url':'http://10.0.0.4:8983/solr'," +
|
||||
" 'node_name':'node1'," +
|
||||
" 'state':'active'," +
|
||||
" 'leader':'true'}," +
|
||||
" 'core_node4':{" +
|
||||
" 'core':'gettingstarted_shard1_replica2'," +
|
||||
" 'r2':{" +
|
||||
" 'core':r2," +
|
||||
" 'base_url':'http://10.0.0.4:7574/solr'," +
|
||||
" 'node_name':'node2'," +
|
||||
" 'state':'active'}}}," +
|
||||
" 'shard2':{" +
|
||||
" 'range':'0-7fffffff'," +
|
||||
" 'state':'active'," +
|
||||
" 'replicas':{" +
|
||||
" 'core_node2':{" +
|
||||
" 'core':'gettingstarted_shard2_replica1'," +
|
||||
" 'r3':{" +
|
||||
" 'core':r3," +
|
||||
" 'base_url':'http://10.0.0.4:8983/solr'," +
|
||||
" 'node_name':'node1'," +
|
||||
" 'state':'active'," +
|
||||
" 'leader':'true'}," +
|
||||
" 'core_node3':{" +
|
||||
" 'core':'gettingstarted_shard2_replica2'," +
|
||||
" 'r4':{" +
|
||||
" 'core':r4," +
|
||||
" 'base_url':'http://10.0.0.4:8987/solr'," +
|
||||
" 'node_name':'node4'," +
|
||||
" 'state':'active'}," +
|
||||
" 'r6':{" +
|
||||
" 'core':r6," +
|
||||
" 'base_url':'http://10.0.0.4:8989/solr'," +
|
||||
" 'node_name':'node3'," +
|
||||
" 'state':'active'}," +
|
||||
" 'r5':{" +
|
||||
" 'core':r5," +
|
||||
" 'base_url':'http://10.0.0.4:7574/solr'," +
|
||||
" 'node_name':'node1'," +
|
||||
" 'state':'active'}}}}}}";
|
||||
|
@ -95,7 +121,6 @@ public class TestRuleSorter extends SolrTestCaseJ4 {
|
|||
Map<String,Object> result = new LinkedHashMap<>();
|
||||
keys.stream().forEach(s -> result.put(s, nodeValues.get(node).get(s)));
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -115,7 +140,6 @@ public class TestRuleSorter extends SolrTestCaseJ4 {
|
|||
List<RuleSorter.ReplicaStat> replicaStats = shardVsReplicaStats.get(shard);
|
||||
if (replicaStats == null) shardVsReplicaStats.put(shard, replicaStats = new ArrayList<>());
|
||||
replicaStats.add(new RuleSorter.ReplicaStat(replicaName, new HashMap<>()));
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -137,7 +161,23 @@ public class TestRuleSorter extends SolrTestCaseJ4 {
|
|||
|
||||
|
||||
System.out.printf(Utils.toJSONString(Utils.getDeepCopy(session.toMap(new LinkedHashMap<>()), 8)));
|
||||
System.out.println(Utils.getDeepCopy(session.getViolations(), 6));
|
||||
Map<String, List<Clause>> violations = session.getViolations();
|
||||
System.out.println(Utils.getDeepCopy(violations, 6));
|
||||
assertEquals(3, violations.size());
|
||||
List<Clause> v = violations.get("node4");
|
||||
assertNotNull(v);
|
||||
assertEquals(v.get(0).tag.name, "nodeRole");
|
||||
v = violations.get("node1");
|
||||
assertNotNull(v);
|
||||
assertEquals(v.get(0).replica.op, Operand.LESS_THAN);
|
||||
assertEquals(v.get(0).replica.val, 2);
|
||||
v = violations.get("node3");
|
||||
assertNotNull(v);
|
||||
assertEquals(v.get(0).replica.op, Operand.LESS_THAN);
|
||||
assertEquals(v.get(0).replica.val, 1);
|
||||
assertEquals(v.get(0).tag.val, "node3");
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue