Improved Stream Router Engine #1305
Conversation
This reverts commit ce1433b. Reverting this as lists are used in all other places unfortunately.
protected final StreamFaultManager streamFaultManager; | ||
protected final StreamMetrics streamMetrics; | ||
protected final TimeLimiter timeLimiter; | ||
protected final long streamProcessingTimeout; |
joschi
Jul 16, 2015
Contributor
Why did you change the visibility of those final fields? They're only being accessed in this very class.
Why did you change the visibility of those final fields? They're only being accessed in this very class.
final List<Rule> regexRules = Lists.newArrayList(); | ||
|
||
for (Stream stream : streams) { | ||
final Boolean sufficient = stream.getMatchingType() == Stream.MatchingType.OR; |
joschi
Jul 16, 2015
Contributor
This could be a primitive boolean
.
This could be a primitive boolean
.
private final Stream stream; | ||
private final StreamRule rule; | ||
private final StreamRuleMatcher matcher; | ||
private final Boolean sufficient; |
joschi
Jul 16, 2015
Contributor
This could be a primitive boolean
.
This could be a primitive boolean
.
joschi
Jul 16, 2015
Contributor
While sufficient
is shorter, I think shortCircuit
or shortCircuitRule
describes better, what this flag denotes in reality.
While sufficient
is shorter, I think shortCircuit
or shortCircuitRule
describes better, what this flag denotes in reality.
@@ -180,7 +216,7 @@ public String getFingerprint() { | |||
|
|||
for (final StreamRule streamRule : stream.getStreamRules()) { | |||
try { | |||
final Rule rule = new Rule(stream, streamRule); | |||
final Rule rule = new Rule(stream, streamRule, null); |
joschi
Jul 16, 2015
Contributor
What meaning would sufficient = null
have in this case? There's also not a single check for Rule#isSufficient() == null
.
What meaning would sufficient = null
have in this case? There's also not a single check for Rule#isSufficient() == null
.
dennisoelkers
Jul 16, 2015
Author
Member
It is not relevant for the reuse of this class in the scope of the test matches, as shortcuts are not taken here and all rules need to be evaluated.
It is not relevant for the reuse of this class in the scope of the test matches, as shortcuts are not taken here and all rules need to be evaluated.
joschi
Jul 16, 2015
Contributor
In this case, the Rule#isSufficient()
method would need to be annotated with @Nullable
and null-checks being introduced on every call of that method.
In this case, the Rule#isSufficient()
method would need to be annotated with @Nullable
and null-checks being introduced on every call of that method.
joschi
Jul 16, 2015
Contributor
TBH, I'd prefer simply using false
here and making Rule#isSufficient()
return a primitive boolean
.
TBH, I'd prefer simply using false
here and making Rule#isSufficient()
return a primitive boolean
.
bernd
Jul 16, 2015
Member
TBH, I'd prefer simply using false
here and making Rule#isSufficient()
return a primitive boolean
.
Agreed, avoids null checks as well. Or is there a specific reason why you use Boolean
instead of boolean
?
TBH, I'd prefer simply using
false
here and makingRule#isSufficient()
return a primitiveboolean
.
Agreed, avoids null checks as well. Or is there a specific reason why you use Boolean
instead of boolean
?
dennisoelkers
Jul 16, 2015
Author
Member
The reason was because of the reuse in the test matching logic. It is misleading to pass any value there. Null checking is a pita too. I will change to a primitive and add a comment.
The reason was because of the reuse in the test matching logic. It is misleading to pass any value there. Null checking is a pita too. I will change to a primitive and add a comment.
dennisoelkers
Jul 16, 2015
Author
Member
Actually I will now replace it with the matching type of the stream. The wording was annoying from the beginning and a boolean flag is just not able to properly represent what it's supposed to do.
Actually I will now replace it with the matching type of the stream. The wording was annoying from the beginning and a boolean flag is just not able to properly represent what it's supposed to do.
bernd
Jul 16, 2015
Member
👍
@@ -83,33 +73,49 @@ public StreamRouterEngine(@Assisted List<Stream> streams, | |||
this.streamProcessingTimeout = streamFaultManager.getStreamProcessingTimeout(); | |||
this.fingerprint = new StreamListFingerprint(streams).getFingerprint(); | |||
|
|||
for (final Stream stream : streams) { | |||
for (final StreamRule streamRule : stream.getStreamRules()) { | |||
this.rulesList = Lists.newArrayList(); |
joschi
Jul 16, 2015
Contributor
This list should be initialized with the (maximum) size presenceRules.size() + exactRules .size() + greaterRules.size() + smallerRules.size() + regexRules.size()
.
This list should be initialized with the (maximum) size presenceRules.size() + exactRules .size() + greaterRules.size() + smallerRules.size() + regexRules.size()
.
final List<Rule> smallerRules = Lists.newArrayList(); | ||
final List<Rule> regexRules = Lists.newArrayList(); | ||
|
||
for (Stream stream : streams) { |
joschi
Jul 16, 2015
Contributor
Maybe instead of sorting the stream rules manually, it would make sense to introduce some kind of complexity rating for the different types of rules, and use a comparator to sort the list of rules accordingly.
Maybe instead of sorting the stream rules manually, it would make sense to introduce some kind of complexity rating for the different types of rules, and use a comparator to sort the list of rules accordingly.
dennisoelkers
Jul 16, 2015
Author
Member
I decided against this, because the effort to sort element by element is much higher than doing it manually.
I decided against this, because the effort to sort element by element is much higher than doing it manually.
joschi
Jul 16, 2015
Contributor
✅
@@ -137,33 +143,63 @@ public String getFingerprint() { | |||
* @return the list of matching streams | |||
*/ | |||
public List<Stream> match(Message message) { |
joschi
Jul 16, 2015
Contributor
Finally changing the method return type to Set<Stream>
would make sense now, I guess. This would also avoid having to copy the matching result at the end of this method.
Finally changing the method return type to Set<Stream>
would make sense now, I guess. This would also avoid having to copy the matching result at the end of this method.
dennisoelkers
Jul 16, 2015
Author
Member
Tried that. Not possible right now, as it would involve external changes of the API.
Tried that. Not possible right now, as it would involve external changes of the API.
joschi
Jul 16, 2015
Contributor
✅
joschi
Jul 16, 2015
Contributor
This is a bit unfortunate because right now this collection is at least copied twice for each message (one time in this method, another time in Message#setStreams()
).
This is a bit unfortunate because right now this collection is at least copied twice for each message (one time in this method, another time in Message#setStreams()
).
dennisoelkers
Jul 16, 2015
Author
Member
Indeed. We should address this. It is beyond me why a List was chosen in the first place.
Indeed. We should address this. It is beyond me why a List was chosen in the first place.
} | ||
}, streamProcessingTimeout, TimeUnit.MILLISECONDS, true); | ||
} catch (Exception e) { | ||
streamFaultManager.registerFailure(rule.getStream()); |
joschi
Jul 16, 2015
Contributor
Logging the exception on DEBUG or TRACE level might help in case of errors.
Logging the exception on DEBUG or TRACE level might help in case of errors.
dennisoelkers
Jul 16, 2015
Author
Member
Done in the StreamFaultManager.registerFailure() method.
Done in the StreamFaultManager.registerFailure() method.
joschi
Jul 16, 2015
Contributor
The exception is not being logged in StreamFaultManager#registerFailure()
.
The exception is not being logged in StreamFaultManager#registerFailure()
.
dennisoelkers
Jul 16, 2015
Author
Member
Right!
Right!
} | ||
|
||
private class Rule { | ||
protected class Rule { |
joschi
Jul 16, 2015
Contributor
Why did you change the visibility level to protected
?
Why did you change the visibility level to protected
?
@@ -58,7 +59,7 @@ public void setUp() throws Exception { | |||
when(streamFaultManager.getStreamProcessingTimeout()).thenReturn(250L); | |||
} | |||
|
|||
private StreamRouterEngine newEngine(List<Stream> streams) { | |||
protected StreamRouterEngine newEngine(List<Stream> streams) { |
joschi
Jul 16, 2015
Contributor
Why was the visibility changed to protected
?
Why was the visibility changed to protected
?
return Lists.newArrayList(result); | ||
} | ||
|
||
private Stream matchWithTimeOut(final Message message, final Rule rule) { |
joschi
Jul 16, 2015
Contributor
Please add @Nullable
.
Please add @Nullable
.
public Boolean isSufficient() { | ||
return sufficient; | ||
} | ||
|
||
public Stream match(Message message) { |
joschi
Jul 16, 2015
Contributor
Please add @Nullable
.
Please add @Nullable
.
} | ||
} | ||
|
||
|
joschi
Jul 16, 2015
Contributor
Unnecessary blank line. 😉
Unnecessary blank line.
streamFaultManager.registerFailure(stream); | ||
} | ||
final Set<Stream> result = Sets.newHashSet(); | ||
final Set<Stream> blackList = Sets.newHashSet(); |
joschi
Jul 16, 2015
Contributor
These sets could be initialized with the (maximum) number of items: Sets#newHashSetWithExpectedSize(streams.size())
These sets could be initialized with the (maximum) number of items: Sets#newHashSetWithExpectedSize(streams.size())
dennisoelkers
Jul 16, 2015
Author
Member
Didn't do this, because it's misleading. We are not expecting it to have that size, it's is the maximum size they could have.
Didn't do this, because it's misleading. We are not expecting it to have that size, it's is the maximum size they could have.
joschi
Jul 16, 2015
Contributor
✅
} | ||
} | ||
} | ||
|
||
this.rulesList = new ImmutableList.Builder<Rule>() |
joschi
Jul 16, 2015
Contributor
Unfortunately this suffers the same problem: Having to resize the underlying array multiple times if the number of rules is high (at least once if the number of rules is greater than 4).
Unfortunately this suffers the same problem: Having to resize the underlying array multiple times if the number of rules is high (at least once if the number of rules is greater than 4).
dennisoelkers
Jul 16, 2015
Author
Member
I prefer immutability in this case. Remember that it's done only during initialization of the stream router (which is done only when the set of stream rules changes).
I prefer immutability in this case. Remember that it's done only during initialization of the stream router (which is done only when the set of stream rules changes).
joschi
Jul 16, 2015
Contributor
✅
joschi
Jul 17, 2015
Contributor
Having looked at the surrounding code, this class is initialized every second (even if the rules haven't been changed) and rulesList
is only used internally in this class, so I think initializing the list with the correct size would yield some improvements and is worth the disadvantage(?) over having a mutable collection instead of an immutable one.
Having looked at the surrounding code, this class is initialized every second (even if the rules haven't been changed) and rulesList
is only used internally in this class, so I think initializing the list with the correct size would yield some improvements and is worth the disadvantage(?) over having a mutable collection instead of an immutable one.
…ed-router-engine Improved StreamRouterEngine
This pull request adds the new stream router engine optimized for best guess minimum cost evaluation.