001/** 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.hbase.hbtop.screen.top; 019 020import java.util.ArrayList; 021import java.util.Collections; 022import java.util.List; 023import java.util.Objects; 024import java.util.stream.Collectors; 025import org.apache.commons.lang3.time.DateFormatUtils; 026import org.apache.hadoop.hbase.ClusterMetrics; 027import org.apache.hadoop.hbase.client.Admin; 028import org.apache.hadoop.hbase.hbtop.Record; 029import org.apache.hadoop.hbase.hbtop.RecordFilter; 030import org.apache.hadoop.hbase.hbtop.field.Field; 031import org.apache.hadoop.hbase.hbtop.field.FieldInfo; 032import org.apache.hadoop.hbase.hbtop.field.FieldValue; 033import org.apache.hadoop.hbase.hbtop.mode.DrillDownInfo; 034import org.apache.hadoop.hbase.hbtop.mode.Mode; 035import org.apache.yetus.audience.InterfaceAudience; 036import org.slf4j.Logger; 037import org.slf4j.LoggerFactory; 038 039 040/** 041 * The data and business logic for the top screen. 042 */ 043@InterfaceAudience.Private 044public class TopScreenModel { 045 046 private static final Logger LOGGER = LoggerFactory.getLogger(TopScreenModel.class); 047 048 private final Admin admin; 049 050 private Mode currentMode; 051 private Field currentSortField; 052 private List<FieldInfo> fieldInfos; 053 private List<Field> fields; 054 055 private Summary summary; 056 private List<Record> records; 057 058 private final List<RecordFilter> filters = new ArrayList<>(); 059 private final List<String> filterHistories = new ArrayList<>(); 060 061 private boolean ascendingSort; 062 063 public TopScreenModel(Admin admin, Mode initialMode) { 064 this.admin = Objects.requireNonNull(admin); 065 switchMode(Objects.requireNonNull(initialMode), null, false); 066 } 067 068 public void switchMode(Mode nextMode, List<RecordFilter> initialFilters, 069 boolean keepSortFieldAndSortOrderIfPossible) { 070 071 currentMode = nextMode; 072 fieldInfos = Collections.unmodifiableList(new ArrayList<>(currentMode.getFieldInfos())); 073 fields = Collections.unmodifiableList(currentMode.getFieldInfos().stream() 074 .map(FieldInfo::getField).collect(Collectors.toList())); 075 076 if (keepSortFieldAndSortOrderIfPossible) { 077 boolean match = fields.stream().anyMatch(f -> f == currentSortField); 078 if (!match) { 079 currentSortField = nextMode.getDefaultSortField(); 080 ascendingSort = false; 081 } 082 } else { 083 currentSortField = nextMode.getDefaultSortField(); 084 ascendingSort = false; 085 } 086 087 clearFilters(); 088 if (initialFilters != null) { 089 filters.addAll(initialFilters); 090 } 091 } 092 093 public void setSortFieldAndFields(Field sortField, List<Field> fields) { 094 this.currentSortField = sortField; 095 this.fields = Collections.unmodifiableList(new ArrayList<>(fields)); 096 } 097 098 /* 099 * HBTop only calls this from a single thread, and if that ever changes, this needs 100 * synchronization 101 */ 102 public void refreshMetricsData() { 103 ClusterMetrics clusterMetrics; 104 try { 105 clusterMetrics = admin.getClusterMetrics(); 106 } catch (Exception e) { 107 LOGGER.error("Unable to get cluster metrics", e); 108 return; 109 } 110 111 refreshSummary(clusterMetrics); 112 refreshRecords(clusterMetrics); 113 } 114 115 private void refreshSummary(ClusterMetrics clusterMetrics) { 116 String currentTime = DateFormatUtils.ISO_8601_EXTENDED_TIME_FORMAT 117 .format(System.currentTimeMillis()); 118 String version = clusterMetrics.getHBaseVersion(); 119 String clusterId = clusterMetrics.getClusterId(); 120 int liveServers = clusterMetrics.getLiveServerMetrics().size(); 121 int deadServers = clusterMetrics.getDeadServerNames().size(); 122 int regionCount = clusterMetrics.getRegionCount(); 123 int ritCount = clusterMetrics.getRegionStatesInTransition().size(); 124 double averageLoad = clusterMetrics.getAverageLoad(); 125 long aggregateRequestPerSecond = clusterMetrics.getLiveServerMetrics().entrySet().stream() 126 .mapToLong(e -> e.getValue().getRequestCountPerSecond()).sum(); 127 128 summary = new Summary(currentTime, version, clusterId, liveServers + deadServers, 129 liveServers, deadServers, regionCount, ritCount, averageLoad, aggregateRequestPerSecond); 130 } 131 132 private void refreshRecords(ClusterMetrics clusterMetrics) { 133 List<Record> records = currentMode.getRecords(clusterMetrics); 134 135 // Filter and sort 136 records = records.stream() 137 .filter(r -> filters.stream().allMatch(f -> f.execute(r))) 138 .sorted((recordLeft, recordRight) -> { 139 FieldValue left = recordLeft.get(currentSortField); 140 FieldValue right = recordRight.get(currentSortField); 141 return (ascendingSort ? 1 : -1) * left.compareTo(right); 142 }).collect(Collectors.toList()); 143 144 this.records = Collections.unmodifiableList(records); 145 } 146 147 public void switchSortOrder() { 148 ascendingSort = !ascendingSort; 149 } 150 151 public boolean addFilter(String filterString, boolean ignoreCase) { 152 RecordFilter filter = RecordFilter.parse(filterString, fields, ignoreCase); 153 if (filter == null) { 154 return false; 155 } 156 157 filters.add(filter); 158 filterHistories.add(filterString); 159 return true; 160 } 161 162 public void clearFilters() { 163 filters.clear(); 164 } 165 166 public boolean drillDown(Record selectedRecord) { 167 DrillDownInfo drillDownInfo = currentMode.drillDown(selectedRecord); 168 if (drillDownInfo == null) { 169 return false; 170 } 171 switchMode(drillDownInfo.getNextMode(), drillDownInfo.getInitialFilters(), true); 172 return true; 173 } 174 175 public Mode getCurrentMode() { 176 return currentMode; 177 } 178 179 public Field getCurrentSortField() { 180 return currentSortField; 181 } 182 183 public List<FieldInfo> getFieldInfos() { 184 return fieldInfos; 185 } 186 187 public List<Field> getFields() { 188 return fields; 189 } 190 191 public Summary getSummary() { 192 return summary; 193 } 194 195 public List<Record> getRecords() { 196 return records; 197 } 198 199 public List<RecordFilter> getFilters() { 200 return Collections.unmodifiableList(filters); 201 } 202 203 public List<String> getFilterHistories() { 204 return Collections.unmodifiableList(filterHistories); 205 } 206}