SOLR-13244: Nodes view fails when a node is temporarily down

This commit is contained in:
Jan Høydahl 2019-03-15 13:30:02 +01:00 committed by GitHub
parent 571b307266
commit 8f29d1eaad
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 85 additions and 45 deletions

View File

@ -120,6 +120,8 @@ Bug Fixes
* SOLR-13284: NullPointerException with 500 http status on omitted or wrong wt param.
It's fixed by fallback to json (Munendra S N via Mikhail Khludnev)
* SOLR-13244: Admin UI Nodes view fails and is empty when a node is temporarily down (janhoy)
Improvements
----------------------
* SOLR-12999: Index replication could delete segments before downloading segments from master if there is not enough

View File

@ -535,6 +535,17 @@ limitations under the License.
color: red;
}
#content #cloud #nodes-content .node-down
{
font-weight: bold;
font-size: 12px;
}
#content #cloud #nodes-content .dead-node
{
background-color: salmon;
}
/* Styling of reload and details buttons */
#content #cloud #controls,
#content #cloud #frame #zk-status-content #zk-controls

View File

@ -107,6 +107,10 @@ function isNumeric(n) {
return !isNaN(parseFloat(n)) && isFinite(n);
}
function coreNameToLabel(name) {
return name.replace(/(.*?)_shard((\d+_?)+)_replica_?[ntp]?(\d+)/, '\$1_s\$2r\$4');
}
var nodesSubController = function($scope, Collections, System, Metrics) {
$scope.pageSize = 10;
$scope.showNodes = true;
@ -160,6 +164,17 @@ var nodesSubController = function($scope, Collections, System, Metrics) {
return nodesInHost[0] === node;
};
// Returns the first live node for this host, to make sure we pick host-level metrics from a live node
$scope.firstLiveNodeForHost = function(key) {
var hostName = key.split(":")[0];
var liveNodesInHost = $scope.filteredNodes.filter(function (key) {
return key.startsWith(hostName);
}).filter(function (key) {
return $scope.live_nodes.includes(key);
});
return liveNodesInHost.length > 0 ? liveNodesInHost[0] : key;
};
// Initializes the cluster state, list of nodes, collections etc
$scope.initClusterState = function() {
var nodes = {};
@ -183,6 +198,7 @@ var nodesSubController = function($scope, Collections, System, Metrics) {
for (var replicaName in replicas) {
var core = replicas[replicaName];
core.name = replicaName;
core.label = coreNameToLabel(core['core']);
core.collection = collection.name;
core.shard = shard.name;
core.shard_state = shard.state;
@ -320,7 +336,15 @@ var nodesSubController = function($scope, Collections, System, Metrics) {
nodesToShow = nodesToShow.concat(hosts[hostName]['nodes']);
}
}
nodesParam = nodesToShow.join(',');
nodesParam = nodesToShow.filter(function (node) {
return live_nodes.includes(node);
}).join(',');
var deadNodes = nodesToShow.filter(function (node) {
return !live_nodes.includes(node);
});
deadNodes.forEach(function (node) {
nodes[node]['dead'] = true;
});
$scope.nextEnabled = $scope.from + pageSize < filteredHosts.length;
$scope.prevEnabled = $scope.from - pageSize >= 0;
nodesToShow.sort();
@ -410,7 +434,6 @@ var nodesSubController = function($scope, Collections, System, Metrics) {
size = (typeof size !== 'undefined') ? size : 0;
core['sizeInBytes'] = size;
core['size'] = bytesToSize(size);
core['label'] = core['core'].replace(/(.*?)_shard((\d+_?)+)_replica_?[ntp]?(\d+)/, '\$1_s\$2r\$4');
if (core['shard_state'] !== 'active' || core['state'] !== 'active') {
// If core state is not active, display the real state, or if shard is inactive, display that
var labelState = (core['state'] !== 'active') ? core['state'] : core['shard_state'];

View File

@ -149,88 +149,92 @@ limitations under the License.
</tr>
</thead>
<tbody>
<tr ng-repeat="key in nodesToShow | orderBy:'key.order'" ng-init="n = nodes[key]">
<td rowspan="{{hosts[n.host].nodes.length}}" ng-show="isFirstNodeForHost(key)">
<div class="host-name">{{n.host}}</div>
<span class="host-spec" ng-show="!showDetails[n.host]">
<span title="{{n.system.system.uptime}}">{{n.system.system.name}}</span>
<span title="free: {{n.memFree}}">{{n.memTotal}}</span>
<span title="{{n.system.jvm.name}} {{n.system.jvm.version}}">Java {{n.system.jvm.spec.version}}</span>
<br/>Load: {{n.loadAvg}}
<tr ng-repeat="key in nodesToShow | orderBy:'key.order'" ng-init="n = nodes[key]; h = nodes[firstLiveNodeForHost(key)]">
<td rowspan="{{hosts[h.host].nodes.length}}" ng-show="isFirstNodeForHost(key)">
<div class="host-name">{{h.host}}</div>
<span class="host-spec" ng-show="!showDetails[h.host]">
<span title="{{h.system.system.uptime}}">{{h.system.system.name}}</span>
<span title="free: {{h.memFree}}">{{h.memTotal}}</span>
<span title="{{h.system.jvm.name}} {{h.system.jvm.version}}">Java {{h.system.jvm.spec.version}}</span>
<br/>Load: {{h.loadAvg}}
</span>
<div class="host-spec" ng-show="showDetails[n.host]">
{{n.system.system.name}} {{n.system.system.version}}, {{n.system.system.availableProcessors}}cpu<br/>
Uptime: {{n.uptime}}<br/>
<span title="Used: {{n.memUsed}} - includes OS file-cache, and it is normal for it to approach 100%">Memory: {{n.memTotal}}</span><br/>
File descriptors: {{n.openFileDescriptorCount}}/{{n.maxFileDescriptorCount}}<br/>
Disk: <span class="{{n.diskUsedPctStyle}}" title="Nodes may use other disks too">{{n.diskTotal}} used: {{n.diskUsedPct}}%</span><br/>
Load: {{n.loadAvg}}
<div class="host-spec" ng-show="showDetails[h.host]">
{{h.system.system.name}} {{h.system.system.version}}, {{h.system.system.availableProcessors}}cpu<br/>
Uptime: {{h.uptime}}<br/>
<span title="Used: {{h.memUsed}} - includes OS file-cache, and it is normal for it to approach 100%">Memory: {{h.memTotal}}</span><br/>
File descriptors: {{h.openFileDescriptorCount}}/{{h.maxFileDescriptorCount}}<br/>
Disk: <span class="{{h.diskUsedPctStyle}}" title="Nodes may use other disks too">{{h.diskTotal}} used: {{h.diskUsedPct}}%</span><br/>
Load: {{h.loadAvg}}
</div>
<div class="node-spec" ng-click="toggleHostDetails(n.host)">
<a ng-show="showDetails[n.host]">hide details...</a>
<a ng-show="!showDetails[n.host]">show details...</a>
<div class="node-spec" ng-click="toggleHostDetails(h.host)">
<a ng-show="showDetails[h.host]">hide details...</a>
<a ng-show="!showDetails[h.host]">show details...</a>
</div>
</td>
<td><div class="node-name"><a href="{{n.base_url}}">{{key.replace(n.host+':', '')}}</a></div>
Uptime: {{n.jvmUptime}}<br/>
<div class="node-spec" ng-show="showDetails[key]">
Java <span title="{{n.system.jvm.jre.vendor}}">{{n.system.jvm.jre.version}}</span><br/>
Solr {{n.system.lucene['solr-impl-version'].split(" ")[0]}}<br>
</div>
<div class="node-spec" ng-click="toggleDetails(key)">
<a ng-show="showDetails[key]">hide details...</a>
<a ng-show="!showDetails[key]">show details...</a>
<td ng-class="{'dead-node': n.dead}"><div class="node-name"><a href="{{n.base_url}}">{{key.replace(n.host+':', '')}}</a></div>
<div ng-show="n.dead" class="node-down">(DEAD)</div>
<div ng-show="!n.dead">
Uptime: {{n.jvmUptime}}<br/>
<div class="node-spec" ng-show="showDetails[key]">
Java <span title="{{n.system.jvm.jre.vendor}}">{{n.system.jvm.jre.version}}</span><br/>
Solr {{n.system.lucene['solr-impl-version'].split(" ")[0]}}<br>
</div>
<div class="node-spec" ng-click="toggleDetails(key)">
<a ng-show="showDetails[key]">hide details...</a>
<a ng-show="!showDetails[key]">show details...</a>
</div>
</div>
</td>
<td>
<div class="node-cpu">
<td ng-class="{'dead-node': n.dead}">
<div class="node-cpu" ng-show="!n.dead">
<span class="{{n.cpuPctStyle}}">{{n.cpuPct}}%</span>
</div>
</td>
<td>
<div class="node-heap" title="total: {{n.heapTotal}} free: {{n.heapFree}} used%: {{n.heapUsedPct}}%">
<td ng-class="{'dead-node': n.dead}">
<div class="node-heap" title="total: {{n.heapTotal}} free: {{n.heapFree}} used%: {{n.heapUsedPct}}%" ng-show="!n.dead">
<span class="{{n.heapUsedPctStyle}}">{{n.heapUsedPct}}%</span>
</div>
<div class="node-spec" ng-show="showDetails[key]">
<div class="node-spec" ng-show="showDetails[key] && !n.dead">
Max: {{n.heapTotal}}<br/>
Used: {{n.heapUsed}}
</div>
</td>
<td class="scroll-height-250">
<td class="scroll-height-250" ng-class="{'dead-node': n.dead}">
<div>
<div class="node-disk" title="Available disk: {{n.diskTotal}} free: {{n.diskFree}} used by this node: {{n.size}}">
<div class="node-disk" title="Available disk: {{n.diskTotal}} free: {{n.diskFree}} used by this node: {{n.size}}" ng-show="!n.dead">
{{n.size}}
</div>
<div class="node-spec" ng-show="showDetails[key]">
<div class="node-spec" ng-show="showDetails[key] && !n.dead">
Total #docs: {{n.numDocs}}<br/>
Avg size/doc: {{n.sizePerDoc}}
</div>
<div id="chart{{n.id}}" ng-show="showDetails[key]"></div>
<div id="chart{{n.id}}" ng-show="showDetails[key] && !n.dead"></div>
</div>
</td>
<td><div class="node-requests" title="1minRate: {{n.req1minRate}} 5minRate: {{n.req5minRate}} 15minRate: {{n.req15minRate}} p75: {{n.reqp75_ms}} p99: {{n.reqp99_ms}}">
<td ng-class="{'dead-node': n.dead}"><div class="node-requests" title="1minRate: {{n.req1minRate}} 5minRate: {{n.req5minRate}} 15minRate: {{n.req15minRate}} p75: {{n.reqp75_ms}} p99: {{n.reqp99_ms}}" ng-show="!n.dead">
RPM: {{n.req15minRate}}<br/>p95: {{n.reqp95_ms}}ms</div>
</td>
<td>
<td ng-class="{'dead-node': n.dead}">
<div ng-show="!n.collections">(none)</div>
<div ng-repeat="c in n.collections | limitTo:showDetails[key]?999:2 track by $index">
<a href="{{n.base_url + '/#/~collections/' + c}}">{{ c }}</a>
<a href="{{h.base_url + '/#/~collections/' + c}}">{{ c }}</a>
</div>
<div class="more" ng-show="n.collections.length > 2 && !showDetails[key]">
<a ng-click="toggleDetails(key)">({{n.collections.length - 2}} more...)</a>
</div>
</td>
<td class="scroll-height-250">
<td class="scroll-height-250" ng-class="{'dead-node': n.dead}">
<div ng-show="!n.cores">(none)</div>
<div ng-repeat="core in n.cores | limitTo:showDetails[key]?999:2 track by $index">
<a class="{{core.leader ? 'leader' : 'replica'}}" href="{{core.base_url + '/#/' + core.core}}">{{ core.label }}</a> ({{core.numDocsHuman}} docs)
<ul class="core-details" ng-show="showDetails[key]">
<div ng-show="!n.dead"><a class="{{core.leader ? 'leader' : 'replica'}}" href="{{core.base_url + '/#/' + core.core + '/core-overview'}}">{{ core.label }}</a> ({{core.numDocsHuman}} docs)</div>
<div ng-show="n.dead">{{ core.label }}</div>
<ul class="core-details" ng-show="showDetails[key] && !n.dead" >
<li>deleted: {{core.deletedDocsHuman}}</li>
<li>warmupTime: {{core.warmupTime}}</li>
<li ng-show="core.numDocs > 0">avg size/doc: {{core.avgSizePerDoc}}</li>
</ul>
</div>
<div class="more" ng-show="n.cores.length > 2 && !showDetails[key]">
<div class="more" ng-show="n.cores.length > 2 && !showDetails[key] && !n.dead">
<a ng-click="toggleDetails(key)">({{n.cores.length - 2}} more...)</a>
</div>
</td>