Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Do not merge: Add ip node spec #6

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open

Conversation

gandhiuw
Copy link

@gandhiuw gandhiuw commented May 9, 2018

Initial pull request for evaluation and discussion

val clusterStateNodeList = if (allowOfflineReferences) allNodes else liveNodes

//First try by matching to the fully qualified domain name
val dnsNodeList: Map[String, String] = dnsNameMap(clusterStateNodeList)
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couldn't think of an idiomatic way to implement this without refactoring each individual filter into a method and use case classes

*/
def unambiguousFragment(fragment: String, nodeComparisonMap: Map[String,String]): Option[String] = {
findUnambigousNode(nodeComparisonMap, (s: String) => s == fragment)
.orElse(findUnambigousNode(nodeComparisonMap, (s: String) => s.contains(fragment)))
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should get rid of the .contains, it prohibits exact IP/Hostname specification. I believe this happens with the existing version of solr cloud manager also.
For e.g specifying --nodes 1.0.0.8 selects nodes 1.0.0.8,1.0.0.81 and 1.0.0.82

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree "contains" is a poor choice for partial name matching. I liked the idea of being able to say --nodes foo2,foo3 or perhaps --nodes 0.8,0.81,0.82 instead of repeating all the identical fully qualified info every time though, and I wasn't too bothered by 1.0.0.8 matching 1.0.0.8 and 1.0.0.81 because if I do actually have both, it should throw the ambiguous node spec message with the conflicting possibilities.

Perhaps a smarter comparison would do literal matches, but within the context of period-separated chunks. Again, just looking to see if there's a single node that matches while using that comparison function.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So the ambiguous node exception will not be thrown every time, IMO it should be. For e.g. if you invoke waitactive with an IP that matches multiple nodes, the call just sums up the replica count across those nodes and returns their state e.g. "All 18 shards were active". IMO we should enforce really tight matching in this case.

Copy link
Contributor

@randomstatistic randomstatistic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I think this is starting to get concealed by the current implementation details, but at a high level, the purpose of this code is to try to find one or more nodes that match a string, according to a sequence of (increasingly fuzzy) comparisons.

For situations where the string is expected to allow matching of multiple nodes ("all", "regex", etc), you work through a list of comparison approaches until one finds non-zero matches, then stop running comparisons and use those. Error if the final result is an empty list.
For situations where the string is expected to match a single node, you try comparison approaches until one gives you exactly one node, then you stop running comparisons and use that. Error if the final result size != 1. (maybe accumulate any ambiguous results for the error message)

@@ -87,34 +88,85 @@ case class SolrState(state: ClusterState, collectionInfo: CollectionInfo, config
lazy val activeReplicas = allReplicas.filter(_.active)
lazy val inactiveReplicas = allReplicas.filterNot(activeReplicas.contains)

/**
* Returns all replicas for a given collection
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment doesn't tell me anything that isn't in the function name.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removing

def replicasFor(collection: String): Seq[SolrReplica] = allReplicas.filter(_.collection == collection)

/**
* Returns all replicas for a given collection, slice combination
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removing

case i =>
//If a comma separated list of nodes is specified, then for each node
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find this comment misleading, as in this context, we're evaluating a single indicator. There's no list.

case i =>
//If a comma separated list of nodes is specified, then for each node
val nodeName = Try(Seq(canonicalNodeName(i, allowOfflineReferences))).recover({
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But on a related note, maybe the Seq wrapper here is confusing and could be removed.

*/
def unambiguousFragment(fragment: String, nodeComparisonMap: Map[String,String]): Option[String] = {
findUnambigousNode(nodeComparisonMap, (s: String) => s == fragment)
.orElse(findUnambigousNode(nodeComparisonMap, (s: String) => s.contains(fragment)))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree "contains" is a poor choice for partial name matching. I liked the idea of being able to say --nodes foo2,foo3 or perhaps --nodes 0.8,0.81,0.82 instead of repeating all the identical fully qualified info every time though, and I wasn't too bothered by 1.0.0.8 matching 1.0.0.8 and 1.0.0.81 because if I do actually have both, it should throw the ambiguous node spec message with the conflicting possibilities.

Perhaps a smarter comparison would do literal matches, but within the context of period-separated chunks. Again, just looking to see if there's a single node that matches while using that comparison function.

* @param comparison function to use for comparison
* @return
*/
def findUnambigousNode(nodeComparisonMap: Map[String,String], comparison: (String) => Boolean): Option[String] = {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe this should be changed to just return the matching node list, and have the test for "single-match" elsewhere. Then we can reuse it in the regex side of things too.

@gandhiuw
Copy link
Author

gandhiuw commented May 9, 2018

IMO, the comparisons should be fuzzy only when the user passes in regular expressions. When using the "--nodes" argument to specify nodes, the expectation should be that his "indicator" match one node only. These indicators could be the exact host name or IP (circumventing the problem of an indicator matching multiple nodes). The changes I've made in this PR enable the user to pass in specific IPs as well (ipNameMap). I'd like to remove the contains altogether and enforce the condition that one indicator match one node only (this happens only in one specific case atm)

@gandhiuw
Copy link
Author

gandhiuw commented May 9, 2018

"For situations where the string is expected to match a single node, you try comparison approaches until one gives you exactly one node, then you stop running comparisons and use that. Error if the final result size != 1. (maybe accumulate any ambiguous results for the error message)"
I've modified the canonicalNodeName method to try matching DNS names first, then IPs and then attempt to resolve the indicator and match it with nodes from the cluster state.

The getNodeListUsingRegEx uses a similar multi-phase approach

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Development

Successfully merging this pull request may close these issues.

3 participants