View Javadoc

1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  package org.apache.hadoop.hbase.hbtop.screen.top;
19  
20  import edu.umd.cs.findbugs.annotations.Nullable;
21  import java.util.ArrayList;
22  import java.util.Collections;
23  import java.util.Comparator;
24  import java.util.List;
25  import java.util.Objects;
26  import org.apache.commons.lang3.time.DateFormatUtils;
27  import org.apache.commons.logging.Log;
28  import org.apache.commons.logging.LogFactory;
29  import org.apache.hadoop.hbase.ClusterStatus;
30  import org.apache.hadoop.hbase.ServerLoad;
31  import org.apache.hadoop.hbase.ServerName;
32  import org.apache.hadoop.hbase.classification.InterfaceAudience;
33  import org.apache.hadoop.hbase.client.Admin;
34  import org.apache.hadoop.hbase.hbtop.Record;
35  import org.apache.hadoop.hbase.hbtop.RecordFilter;
36  import org.apache.hadoop.hbase.hbtop.field.Field;
37  import org.apache.hadoop.hbase.hbtop.field.FieldInfo;
38  import org.apache.hadoop.hbase.hbtop.field.FieldValue;
39  import org.apache.hadoop.hbase.hbtop.mode.DrillDownInfo;
40  import org.apache.hadoop.hbase.hbtop.mode.Mode;
41  
42  /**
43   * The data and business logic for the top screen.
44   */
45  @InterfaceAudience.Private
46  public class TopScreenModel {
47  
48    private static final Log LOG = LogFactory.getLog(TopScreenModel.class);
49  
50    private final Admin admin;
51  
52    private Mode currentMode;
53    private Field currentSortField;
54    private List<FieldInfo> fieldInfos;
55    private List<Field> fields;
56  
57    private Summary summary;
58    private List<Record> records;
59  
60    private final List<RecordFilter> filters = new ArrayList<>();
61    private final List<String> filterHistories = new ArrayList<>();
62  
63    private boolean ascendingSort;
64  
65    public TopScreenModel(Admin admin, Mode initialMode, @Nullable List<Field> initialFields,
66      @Nullable Field initialSortField, @Nullable Boolean initialAscendingSort,
67      @Nullable List<RecordFilter> initialFilters) {
68      this.admin = Objects.requireNonNull(admin);
69      switchMode(Objects.requireNonNull(initialMode), initialSortField, false, initialFields,
70        initialAscendingSort, initialFilters);
71    }
72  
73    public void switchMode(Mode nextMode, boolean keepSortFieldAndSortOrderIfPossible,
74      List<RecordFilter> initialFilters) {
75      switchMode(nextMode, null, keepSortFieldAndSortOrderIfPossible, null, null, initialFilters);
76    }
77  
78    public void switchMode(Mode nextMode, Field initialSortField,
79      boolean keepSortFieldAndSortOrderIfPossible, @Nullable List<Field> initialFields,
80      @Nullable Boolean initialAscendingSort, @Nullable List<RecordFilter> initialFilters) {
81      currentMode = nextMode;
82      fieldInfos = Collections.unmodifiableList(new ArrayList<>(currentMode.getFieldInfos()));
83  
84      fields = new ArrayList<>();
85      for (FieldInfo fieldInfo : currentMode.getFieldInfos()) {
86        if (initialFields != null) {
87          if (initialFields.contains(fieldInfo.getField())) {
88            fields.add(fieldInfo.getField());
89          }
90        } else {
91          fields.add(fieldInfo.getField());
92        }
93      }
94      fields = Collections.unmodifiableList(fields);
95  
96      if (keepSortFieldAndSortOrderIfPossible) {
97        boolean match = false;
98        for (Field field : fields) {
99          if (field == currentSortField) {
100           match = true;
101           break;
102         }
103       }
104 
105       if (!match) {
106         if (initialSortField != null && initialAscendingSort != null) {
107           currentSortField = initialSortField;
108           ascendingSort = initialAscendingSort;
109         } else {
110           currentSortField = nextMode.getDefaultSortField();
111           ascendingSort = false;
112         }
113       }
114     } else {
115       if (initialSortField != null && initialAscendingSort != null) {
116         currentSortField = initialSortField;
117         ascendingSort = initialAscendingSort;
118       } else {
119         currentSortField = nextMode.getDefaultSortField();
120         ascendingSort = false;
121       }
122     }
123 
124     clearFilters();
125     if (initialFilters != null) {
126       filters.addAll(initialFilters);
127     }
128   }
129 
130   public void setSortFieldAndFields(Field sortField, List<Field> fields) {
131     this.currentSortField = sortField;
132     this.fields = Collections.unmodifiableList(new ArrayList<>(fields));
133   }
134 
135   /*
136    * HBTop only calls this from a single thread, and if that ever changes, this needs
137    * synchronization
138    */
139   public void refreshMetricsData() {
140     ClusterStatus clusterStatus;
141     try {
142       clusterStatus = admin.getClusterStatus();
143     } catch (Exception e) {
144       LOG.error("Unable to get cluster status", e);
145       return;
146     }
147 
148     refreshSummary(clusterStatus);
149     refreshRecords(clusterStatus);
150   }
151 
152   private void refreshSummary(ClusterStatus clusterStatus) {
153     String currentTime = DateFormatUtils.ISO_8601_EXTENDED_TIME_FORMAT
154       .format(System.currentTimeMillis());
155     String version = clusterStatus.getHBaseVersion();
156     String clusterId = clusterStatus.getClusterId();
157     int liveServers = clusterStatus.getServersSize();
158     int deadServers = clusterStatus.getDeadServerNames().size();
159     int regionCount = clusterStatus.getRegionsCount();
160     int ritCount = clusterStatus.getRegionsInTransition().size();
161     double averageLoad = clusterStatus.getAverageLoad();
162     long aggregateRequestPerSecond = 0;
163     for (ServerName sn: clusterStatus.getServers()) {
164       ServerLoad sl = clusterStatus.getLoad(sn);
165       aggregateRequestPerSecond += sl.getNumberOfRequests();
166     }
167     summary = new Summary(currentTime, version, clusterId, liveServers + deadServers,
168       liveServers, deadServers, regionCount, ritCount, averageLoad, aggregateRequestPerSecond);
169   }
170 
171   private void refreshRecords(ClusterStatus clusterStatus) {
172     // Filter
173     List<Record> records = new ArrayList<>();
174     for (Record record : currentMode.getRecords(clusterStatus)) {
175       boolean filter = false;
176       for (RecordFilter recordFilter : filters) {
177         if (!recordFilter.execute(record)) {
178           filter = true;
179           break;
180         }
181       }
182       if (!filter) {
183         records.add(record);
184       }
185     }
186 
187     // Sort
188     Collections.sort(records, new Comparator<Record>() {
189       @Override
190       public int compare(Record recordLeft, Record recordRight) {
191         FieldValue left = recordLeft.get(currentSortField);
192         FieldValue right = recordRight.get(currentSortField);
193         return (ascendingSort ? 1 : -1) * left.compareTo(right);
194       }
195     });
196 
197     this.records = Collections.unmodifiableList(records);
198   }
199 
200   public void switchSortOrder() {
201     ascendingSort = !ascendingSort;
202   }
203 
204   public boolean addFilter(String filterString, boolean ignoreCase) {
205     RecordFilter filter = RecordFilter.parse(filterString, fields, ignoreCase);
206     if (filter == null) {
207       return false;
208     }
209 
210     filters.add(filter);
211     filterHistories.add(filterString);
212     return true;
213   }
214 
215   public void clearFilters() {
216     filters.clear();
217   }
218 
219   public boolean drillDown(Record selectedRecord) {
220     DrillDownInfo drillDownInfo = currentMode.drillDown(selectedRecord);
221     if (drillDownInfo == null) {
222       return false;
223     }
224     switchMode(drillDownInfo.getNextMode(), true, drillDownInfo.getInitialFilters());
225     return true;
226   }
227 
228   public Mode getCurrentMode() {
229     return currentMode;
230   }
231 
232   public Field getCurrentSortField() {
233     return currentSortField;
234   }
235 
236   public List<FieldInfo> getFieldInfos() {
237     return fieldInfos;
238   }
239 
240   public List<Field> getFields() {
241     return fields;
242   }
243 
244   public Summary getSummary() {
245     return summary;
246   }
247 
248   public List<Record> getRecords() {
249     return records;
250   }
251 
252   public List<RecordFilter> getFilters() {
253     return Collections.unmodifiableList(filters);
254   }
255 
256   public List<String> getFilterHistories() {
257     return Collections.unmodifiableList(filterHistories);
258   }
259 }